8000 Support PHP 8 attributes at the parameter level by mnapoli · Pull Request #741 · PHP-DI/PHP-DI · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Support PHP 8 attributes at the parameter level #741

New issue

Have a question about this project?< 8000 /strong> Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions doc/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,38 @@ class Example
private $property3;

/**
* Attribute specifying exactly what to inject on the constructor:
* The constructor is of course always called, but the
* #[Inject] attribute can be used on a parameter
* to specify what to inject.
*/
#[Inject(['db.host', 'db.name'])]
public function __construct($param1, $param2)
public function __construct(Foo $foo, #[Inject('db.host')] $dbHost)
{
}

/**
* Attribute combined with PHP types:
* #[Inject] tells PHP-DI to call the method.
* By default, PHP-DI uses the PHP types to find the service to inject:
*/
#[Inject]
public function method1(Foo $param)
{
}

/**
* #[Inject] can be used at the parameter level to
* specify what to inject.
* Note: #[Inject] *must be place* on the function too.
*/
#[Inject]
public function method2(#[Inject('db.host')] $param)
{
}

/**
* Explicit definition of the entries to inject:
*/
#[Inject(['db.host', 'db.name'])]
public function method2($param1, $param2)
public function method3($param1, $param2)
{
}

Expand All @@ -85,7 +97,7 @@ class Example
* (types are used for the other parameters):
*/
#[Inject(['param2' => 'db.host'])]
public function method3(Foo $param1, $param2)
public function method4(Foo $param1, $param2)
{
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Attribute/Inject.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*
* @author Matthieu Napoli <matthieu@mnapoli.fr>
*/
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)]
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)]
final class Inject
{
/**
Expand Down
22 changes: 9 additions & 13 deletions src/Definition/Source/AttributeBasedAutowiring.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,22 +179,10 @@ private function readMethods(ReflectionClass $class, ObjectDefinition $objectDef
}
}

/**
* @throws InvalidAnnotation
*/
private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection
{
// Look for #[Inject] attribute
try {
$attribute = $method->getAttributes(Inject::class)[0] ?? null;
} catch (Throwable $e) {
throw new InvalidAnnotation(sprintf(
'#[Inject] annotation on %s::%s() is malformed. %s',
$method->getDeclaringClass()->getName(),
$method->getName(),
$e->getMessage()
), 0, $e);
}
$attribute = $method->getAttributes(Inject::class)[0] ?? null;

if ($attribute) {
/** @var Inject $inject */
Expand Down Expand Up @@ -228,6 +216,14 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection
*/
private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters) : ?string
{
// Let's check if this parameter has an #[Inject] attribute
$attribute = $parameter->getAttributes(Inject::class)[0] ?? null;
if ($attribute) {
/** @var Inject $inject */
$inject = $attribute->newInstance();
return $inject->getName();
}

// #[Inject] has definition for this parameter (by index, or by name)
if (isset($annotationParameters[$parameterIndex])) {
return $annotationParameters[$parameterIndex];
Expand Down
29 changes: 21 additions & 8 deletions tests/IntegrationTest/Definitions/AttributeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use DI\Test\IntegrationTest\Definitions\AttributesTest\PropertyInjection;
use ProxyManager\Proxy\LazyLoadingInterface;
use function DI\autowire;
use function DI\create;

/**
* Test definitions autowired with attributes.
Expand All @@ -32,12 +33,13 @@ public function test_injectable_annotation_is_not_required(ContainerBuilder $bui
/**
* @dataProvider provideContainer
*/
public function test_supports_autowiring(ContainerBuilder $builder)
public function test_constructor_injection(ContainerBuilder $builder)
{
$builder->useAttributes(true);
$builder->addDefinitions([
'foo' => 'bar',
'lazyService' => autowire(\stdClass::class)->lazy(),
'attribute' => create(\stdClass::class),
]);
$container = $builder->build();

Expand All @@ -49,13 +51,14 @@ public function test_supports_autowiring(ContainerBuilder $builder)
self::assertInstanceOf(\stdClass::class, $object->lazyService);
self::assertInstanceOf(LazyLoadingInterface::class, $object->lazyService);
self::assertFalse($object->lazyService->isProxyInitialized());
self::assertSame($container->get('attribute'), $object->attribute);
self::assertEquals('hello', $object->optionalValue);
}

/**
* @dataProvider provideContainer
*/
public function test_constructor_injection(ContainerBuilder $builder)
public function test_supports_autowiring(ContainerBuilder $builder)
{
$builder->useAttributes(true);
$container = $builder->build();
Expand Down Expand Up @@ -96,6 +99,7 @@ public function test_method_injection(ContainerBuilder $builder)
$builder->addDefinitions([
'foo' => 'bar',
'lazyService' => autowire(\stdClass::class)->lazy(),
'attribute' => create(\stdClass::class),
]);
$container = $builder->build();

Expand All @@ -107,6 +111,7 @@ public function test_method_injection(ContainerBuilder $builder)
self::assertInstanceOf(\stdClass::class, $object->lazyService);
self::assertInstanceOf(LazyLoadingInterface::class, $object->lazyService);
self::assertFalse($object->lazyService->isProxyInitialized());
self::assertSame($container->get('attribute'), $object->attribute);
self::assertEquals('hello', $object->optionalValue);
}
}
Expand Down Expand Up @@ -136,12 +141,13 @@ public function __construct(stdClass $entry)
class ConstructorInjection
{
public $value;
public $scalarValue;
public $typedValue;
public $typedOptionalValue;
/** @var \ProxyManager\Proxy\LazyLoadingInterface */
public string $scalarValue;
public stdClass $typedValue;
public ?stdClass $typedOptionalValue;
/** @var stdClass&\ProxyManager\Proxy\LazyLoadingInterface */
public $lazyService;
public $optionalValue;
public stdClass $attribute;
public string $optionalValue;

#[Inject(['value' => 'foo', 'scalarValue' => 'foo', 'lazyService' => 'lazyService'])]
public function __construct(
Expand All @@ -150,13 +156,16 @@ public function __construct(
6D40 \stdClass $typedValue,
\stdClass $typedOptionalValue = null,
\stdClass $lazyService,
$optionalValue = 'hello'
#[Inject('attribute')]
\stdClass $attribute,
string $optionalValue = 'hello'
) {
$this->value = $value;
$this->scalarValue = $scalarValue;
$this->typedValue = $typedValue;
$this->typedOptionalValue = $typedOptionalValue;
$this->lazyService = $lazyService;
$this->attribute = $attribute;
$this->optionalValue = $optionalValue;
}
}
Expand All @@ -181,6 +190,7 @@ class MethodInjection
public $typedOptionalValue;
/** @var \ProxyManager\Proxy\LazyLoadingInterface */
public $lazyService;
public stdClass $attribute;
public $optionalValue;

#[Inject(['value' => 'foo', 'scalarValue' => 'foo', 'lazyService' => 'lazyService'])]
Expand All @@ -190,13 +200,16 @@ public function method(
$untypedValue,
\stdClass $typedOptionalValue = null,
\stdClass $lazyService,
#[Inject('attribute')]
stdClass $attribute,
$optionalValue = 'hello'
) {
$this->value = $value;
$this->scalarValue = $scalarValue;
$this->untypedValue = $untypedValue;
$this->typedOptionalValue = $typedOptionalValue;
$this->lazyService = $lazyService;
$this->attribute = $attribute;
$this->optionalValue = $optionalValue;
}
}
0