Skip to content

Commit

Permalink
Add autowiring-support for PHP7.4 typed properties
Browse files Browse the repository at this point in the history
The current implementation prioritizes `@var` and the `name` property of
the `@Inject` annotation over the type of the property. This allows to
still inject custom-named entries into the properties even in the
presence of types.
  • Loading branch information
bzikarsky committed Mar 20, 2020
1 parent ee05245 commit 9ef7b48
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 2 deletions.
12 changes: 11 additions & 1 deletion src/Definition/Source/AnnotationBasedAutowiring.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use PhpDocReader\PhpDocReader;
use ReflectionClass;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionParameter;
use ReflectionProperty;
use UnexpectedValueException;
Expand Down Expand Up @@ -125,9 +126,18 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de
return;
}

// @Inject("name") or look for @var content
// Try to @Inject("name") or look for @var content
$entryName = $annotation->getName() ?: $this->getPhpDocReader()->getPropertyClass($property);

// Try using PHP7.4 typed properties
if (\PHP_VERSION_ID > 70400
&& $entryName === null
&& $property->getType() instanceof ReflectionNamedType
&& (class_exists($property->getType()->getName()) || interface_exists($property->getType()->getName()))
) {
$entryName = $property->getType()->getName();
}

if ($entryName === null) {
throw new InvalidAnnotation(sprintf(
'@Inject found on property %s::%s but unable to guess what to inject, use a @var annotation',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture4;
use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture5;
use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixtureChild;
use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixtureScalarTypedProperty;
use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixtureTypedProperties;
use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationInjectableFixture;
use PHPUnit\Framework\TestCase;

Expand Down Expand Up @@ -63,6 +65,30 @@ public function testUnguessableProperty()
(new AnnotationBasedAutowiring)->autowire(AnnotationFixture4::class);
}

public function testTypedProperty()
{
if (PHP_VERSION_ID < 70400) {
$this->markTestSkipped('Typed properties support requires PHP7.4');
}

$definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureTypedProperties::class);

$this->assertNotHasPropertyInjection($definition, 'typeAndNoInject');
$this->assertHasPropertyInjection($definition, 'typedAndInject', AnnotationFixture2::class);
$this->assertHasPropertyInjection($definition, 'typedAndVar', AnnotationFixture3::class);
$this->assertHasPropertyInjection($definition, 'typedAndNamed', 'name');
}

public function testScalarTypedPropertiesFail()
{
if (PHP_VERSION_ID < 70400) {
$this->markTestSkipped('Typed properties support requires PHP7.4');
}

$this->expectException(\DI\Definition\Exception\InvalidAnnotation::class);
(new AnnotationBasedAutowiring)->autowire(AnnotationFixtureScalarTypedProperty::class);
}

public function testConstructor()
{
$definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class);
Expand Down Expand Up @@ -254,11 +280,21 @@ private function getMethodInjection(ObjectDefinition $definition, $name)
return null;
}

private function assertHasPropertyInjection(ObjectDefinition $definition, $propertyName)
private function assertHasPropertyInjection(ObjectDefinition $definition, $propertyName, ?string $expectedType = null)
{
$propertyInjections = $definition->getPropertyInjections();
foreach ($propertyInjections as $propertyInjection) {
if ($propertyInjection->getPropertyName() === $propertyName) {

if ($expectedType !== null) {
$this->assertInstanceOf(Reference::class, $propertyInjection->getValue());
$this->assertEquals(
$expectedType,
$propertyInjection->getValue()->getTargetEntryName(),
'Property injected with the right type'
);
}

return;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace DI\Test\UnitTest\Definition\Source\Fixtures;

class AnnotationFixtureScalarTypedProperty
{
/**
* @Inject
*/
protected int $scalarTypeAndInject;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace DI\Test\UnitTest\Definition\Source\Fixtures;

class AnnotationFixtureTypedProperties
{
protected AnnotationFixture2 $typedButNoInject;

/**
* @Inject
*/
protected AnnotationFixture2 $typedAndInject;

/**
* @Inject
* @var AnnotationFixture3
*/
protected AnnotationFixture2 $typedAndVar;

/**
* @Inject("name")
*/
protected AnnotationFixture2 $typedAndNamed;
}

0 comments on commit 9ef7b48

Please sign in to comment.