From 1c0a168b4c92386e00a02c4bd64fe24f4f7d717d Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 1 Aug 2020 22:06:34 +0200 Subject: [PATCH 01/45] Drop support for phpdoc types with @Inject by moving to PHP 7.4+ We can get rid of PhpDocReader --- .travis.yml | 13 +--- composer.json | 11 +-- doc/annotations.md | 26 ++++--- doc/autowiring.md | 2 +- doc/best-practices.md | 3 +- doc/container.md | 3 +- doc/frameworks/symfony2.md | 3 +- doc/frameworks/zf1.md | 3 +- doc/frameworks/zf2.md | 3 +- doc/migration/7.0.md | 64 ++++++++++++++++ .../Source/AnnotationBasedAutowiring.php | 74 +++++++------------ src/Invoker/FactoryParameterResolver.php | 1 + .../Annotations/AnnotationsTest.php | 33 --------- tests/IntegrationTest/Annotations/B.php | 9 +-- tests/IntegrationTest/Annotations/Child.php | 3 +- .../Annotations/InjectWithUseStatements.php | 30 -------- .../InjectWithUseStatements2.php | 17 ----- .../Annotations/NotFoundVarAnnotation.php | 16 ---- tests/IntegrationTest/ContainerDebugTest.php | 14 ++-- .../IntegrationTest/ContainerInjectOnTest.php | 3 +- .../Definitions/AnnotationTest.php | 20 +---- .../Definitions/WildcardDefinitionsTest.php | 3 +- tests/IntegrationTest/Fixtures/Class1.php | 12 +-- .../Fixtures/InheritanceTest/BaseClass.php | 17 +---- .../Fixtures/InheritanceTest/Dependency.php | 5 +- .../Fixtures/InheritanceTest/SubClass.php | 3 +- .../Source/AnnotationBasedAutowiringTest.php | 35 ++------- .../Source/Fixtures/AnnotationFixture.php | 6 +- .../Source/Fixtures/AnnotationFixture3.php | 4 +- .../Source/Fixtures/AnnotationFixture5.php | 8 +- .../AnnotationFixtureTypedProperties.php | 6 -- .../Fixtures/Class1CircularDependencies.php | 3 +- .../Fixtures/Class2CircularDependencies.php | 4 +- 33 files changed, 159 insertions(+), 298 deletions(-) create mode 100644 doc/migration/7.0.md delete mode 100644 tests/IntegrationTest/Annotations/InjectWithUseStatements.php delete mode 100644 tests/IntegrationTest/Annotations/InjectWithUseStatements/InjectWithUseStatements2.php delete mode 100644 tests/IntegrationTest/Annotations/NotFoundVarAnnotation.php diff --git a/.travis.yml b/.travis.yml index 103e3e6df..a0cd70964 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,8 +7,6 @@ notifications: on_success: never php: - - 7.2 - - 7.3 - 7.4 - nightly @@ -17,7 +15,7 @@ matrix: allow_failures: - php: nightly include: - - php: 7.2 + - php: 7.4 env: dependencies=lowest cache: @@ -25,16 +23,11 @@ cache: - $HOME/.composer/cache before_script: - - if [[ $(phpenv version-name) == '7.2' ]]; then composer require satooshi/php-coveralls '~1.0' -n ; fi - - if [[ $(phpenv version-name) != '7.2' ]]; then composer install -n ; fi + - composer install -n - if [ "$dependencies" = "lowest" ]; then composer update --prefer-lowest --prefer-stable -n; fi; - echo "extension = apcu.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - echo 'apc.enable_cli = 1' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini script: - - if [[ $(phpenv version-name) == '7.2' ]]; then vendor/bin/phpunit --coverage-clover clover.xml ; fi - - if [[ $(phpenv version-name) != '7.2' ]]; then vendor/bin/phpunit ; fi + - vendor/bin/phpunit - if [[ $(phpenv version-name) == '7.4' ]]; then vendor/bin/phpstan analyse -c phpstan.neon ; fi - -after_script: - - if [[ $(phpenv version-name) == '7.2' ]]; then php vendor/bin/coveralls -v ; fi diff --git a/composer.json b/composer.json index 693d3ff50..134ac2a70 100644 --- a/composer.json +++ b/composer.json @@ -25,15 +25,14 @@ "phpstan": "phpstan analyse -l 5 -c phpstan.neon src" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "psr/container": "^1.0", "php-di/invoker": "^2.0", - "php-di/phpdoc-reader": "^2.0.1", "opis/closure": "^3.5.5" }, "require-dev": { - "phpunit/phpunit": "^8.5", - "mnapoli/phpunit-easymock": "^1.2", + "phpunit/phpunit": "^9.3-dev", + "mnapoli/phpunit-easymock": "^1.3", "doctrine/annotations": "~1.2", "ocramius/proxy-manager": "~2.0.2", "friendsofphp/php-cs-fixer": "^2.4", @@ -45,5 +44,7 @@ "suggest": { "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" - } + }, + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/doc/annotations.md b/doc/annotations.md index 5efd7dc06..0d545c5e6 100644 --- a/doc/annotations.md +++ b/doc/annotations.md @@ -23,11 +23,11 @@ Then you need to [configure the `ContainerBuilder`](container-configuration.md) $containerBuilder->useAnnotations(true); ``` -Annotations are written in PHP docblock comments. They are used by a lot of modern libraries and frameworks, like [Doctrine](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html), [Symfony](http://symfony.com/), [PHPUnit](http://www.phpunit.de/)… +Annotations are written in PHP docblock comments. They are used by a lot of modern libraries and frameworks, like [Doctrine](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html), [Symfony](http://symfony.com/) and more. ## @Inject -`@Inject` lets you define where PHP-DI should inject something, and what it should inject. You can optionally combine it with `@var` and `@param` phpdoc tags to define what should be injected. +`@Inject` lets you define where PHP-DI should inject something, and optionally what it should inject. It can be used on: @@ -37,18 +37,19 @@ It can be used on: *Note: property injections occur after the constructor is executed, so any injectable property will be null inside `__construct`.* +**Since PHP-DI 7, `@Inject` will ignore types declared in phpdoc. Only types specified in PHP code will be considered.** + Here is an example of all possible uses of the `@Inject` annotation: ```php class Example { /** - * Annotation combined with phpdoc: + * Annotation combined with a type on the property: * * @Inject - * @var Foo */ - private $property1; + private Foo $property1; /** * Explicit definition of the entry to inject: @@ -58,18 +59,16 @@ class Example private $property2; /** - * Annotation combined with phpdoc: + * Annotation specifying exactly what to inject: * - * @Inject - * @param Foo $param1 - * @param Bar $param2 + * @Inject({"db.host", "db.name"}) */ public function __construct($param1, $param2) { } /** - * Annotation combined with the type-hint: + * Annotation combined with PHP types: * * @Inject */ @@ -87,7 +86,8 @@ class Example } /** - * Explicit definition of parameters by their name: + * Explicit definition of parameters by their name + * (types are used for the other parameters): * * @Inject({"param2" = "db.host"}) */ @@ -103,8 +103,10 @@ class Example - you must use double quotes (`"`) instead of single quotes(`'`), for example: `@Inject("foo")` - what's inside `@Inject()` must be in quotes, even if it's a class name: `@Inject("Acme\Blog\ArticleRepository")` -- when using `@Inject` in combination with `@var` or `@param`, make sure the class name is correctly imported if using namespaces (a good IDE will show warnings if not) - `@Inject` is not meant to be used on the method to call with [`Container::call()`](container.md#call) (it will be ignored) +- **Since PHP-DI 7, `@Inject` will ignore types declared in phpdoc. Only types specified in PHP code will be considered.** + +Note that `@Inject` is implicit on all constructors. ## Injectable diff --git a/doc/autowiring.md b/doc/autowiring.md index abffd7c70..ff8912351 100644 --- a/doc/autowiring.md +++ b/doc/autowiring.md @@ -28,7 +28,7 @@ class UserRegistrationService } ``` -When PHP-DI needs to create the `UserRegistrationService`, it detects that the constructor takes a `UserRepository` object (using the [type hinting](http://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration)). +When PHP-DI needs to create the `UserRegistrationService`, it detects that the constructor takes a `UserRepository` object (using the [type declarations](http://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration)). **Without any configuration**, PHP-DI will create a `UserRepository` instance (if it wasn't already created) and pass it as a constructor parameter. The equivalent raw PHP code would be: diff --git a/doc/best-practices.md b/doc/best-practices.md index 0f46e316b..c59cd7381 100644 --- a/doc/best-practices.md +++ b/doc/best-practices.md @@ -50,9 +50,8 @@ class UserController { /** * @Inject - * @var FormFactoryInterface */ - private $formFactory; + private FormFactoryInterface $formFactory; public function createForm($type, $data, $options) { diff --git a/doc/container.md b/doc/container.md index d079e022a..a08546545 100644 --- a/doc/container.md +++ b/doc/container.md @@ -190,9 +190,8 @@ class UserController extends BaseController { /** * @Inject - * @var SomeService */ - private $someService; + private SomeService $someService; public function __construct() { diff --git a/doc/frameworks/symfony2.md b/doc/frameworks/symfony2.md index 7127b2bbc..76b85741e 100644 --- a/doc/frameworks/symfony2.md +++ b/doc/frameworks/symfony2.md @@ -80,9 +80,8 @@ class ProductController { /** * @Inject - * @var ProductService */ - private $productService; + private ProductService $productService; public function clearAction() { diff --git a/doc/frameworks/zf1.md b/doc/frameworks/zf1.md index e5fa7f666..14205d345 100644 --- a/doc/frameworks/zf1.md +++ b/doc/frameworks/zf1.md @@ -54,9 +54,8 @@ class GuestbookController extends Zend_Controller_Action /** * This dependency will be injected by PHP-DI * @Inject - * @var Application_Service_GuestbookService */ - private $guestbookService; + private Application_Service_GuestbookService $guestbookService; public function indexAction() { diff --git a/doc/frameworks/zf2.md b/doc/frameworks/zf2.md index 57b513461..a577c55a7 100644 --- a/doc/frameworks/zf2.md +++ b/doc/frameworks/zf2.md @@ -49,9 +49,8 @@ class GuestbookController extends AbstractActionController /** * This dependency will be injected by PHP-DI * @Inject - * @var \Application\Service\GuestbookService */ - private $guestbookService; + private \Application\Service\GuestbookService $guestbookService; public function indexAction() { diff --git a/doc/migration/7.0.md b/doc/migration/7.0.md new file mode 100644 index 000000000..0e2d10440 --- /dev/null +++ b/doc/migration/7.0.md @@ -0,0 +1,64 @@ +--- +layout: documentation +current_menu: v7 +--- + +# Migrating from PHP-DI 6.x to 7.0 + +PHP-DI 7.0 is a new major version that comes with backward compatibility breaks. + +This guide will help you migrate from a 6.x version to 7.0. It will only explain backward compatibility breaks, it will not present the new features (read the release notes or the blog post for that). + +## PHP version + +PHP-DI now requires PHP 7.4 or greater. + +## PHPdoc types are ignored by `@Inject` + +Now that PHP 7.4 and up supports typed properties, PHP-DI will stop reading types from phpdoc. + +Here is an example on how to migrate from PHP-DI 6 to PHP-DI 7: + +- **before:** + +```php +class Example +{ + /** + * @Inject + * @var Foo + */ + private $property; + + /** + * @Inject + * @param Foo $param + */ + public function method($param) + { + } +} +``` + +- **after:** + +```php +class Example +{ + /** + * @Inject + */ + private Foo $property; + + /** + * @Inject + */ + public function method(Foo $param) + { + } +} +``` + +## Internal changes + +If you were overriding or extending some internal classes of PHP-DI, be aware that they may have changed. diff --git a/src/Definition/Source/AnnotationBasedAutowiring.php b/src/Definition/Source/AnnotationBasedAutowiring.php index 508e00745..c4fca7f4e 100644 --- a/src/Definition/Source/AnnotationBasedAutowiring.php +++ b/src/Definition/Source/AnnotationBasedAutowiring.php @@ -15,7 +15,6 @@ use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Annotations\SimpleAnnotationReader; use InvalidArgumentException; -use PhpDocReader\PhpDocReader; use ReflectionClass; use ReflectionMethod; use ReflectionNamedType; @@ -33,26 +32,11 @@ */ class AnnotationBasedAutowiring implements DefinitionSource, Autowiring { - /** - * @var Reader - */ - private $annotationReader; - - /** - * @var PhpDocReader - */ - private $phpDocReader; + private ?Reader $annotationReader = null; /** - * @var bool + * @throws InvalidAnnotation */ - private $ignorePhpDocErrors; - - public function __construct($ignorePhpDocErrors = false) - { - $this->ignorePhpDocErrors = (bool) $ignorePhpDocErrors; - } - public function autowire(string $name, ObjectDefinition $definition = null) { $className = $definition ? $definition->getClassName() : $name; @@ -118,6 +102,9 @@ private function readProperties(ReflectionClass $class, ObjectDefinition $defini } } + /** + * @throws InvalidAnnotation + */ private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, $classname = null) { // Look for @Inject annotation @@ -126,21 +113,25 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de return; } - // 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(); + // Try to @Inject("name") or look for the property type + $entryName = $annotation->getName(); + + // Try using typed properties + $propertyType = $property->getType(); + if ($entryName === null && $propertyType instanceof ReflectionNamedType) { + if (! class_exists($propertyType->getName()) && ! interface_exists($propertyType->getName())) { + throw new InvalidAnnotation(sprintf( + '@Inject found on property %s::%s but unable to guess what to inject, the type of the property does not look like a valid class or interface name', + $property->getDeclaringClass()->getName(), + $property->getName() + )); + } + $entryName = $propertyType->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', + '@Inject found on property %s::%s but unable to guess what to inject, please add a type to the property', $property->getDeclaringClass()->getName(), $property->getName() )); @@ -177,9 +168,9 @@ private function readMethods(ReflectionClass $class, ObjectDefinition $objectDef } /** - * @return MethodInjection|null + * @throws InvalidAnnotation */ - private function getMethodInjection(ReflectionMethod $method) + private function getMethodInjection(ReflectionMethod $method): ?MethodInjection { // Look for @Inject annotation try { @@ -236,20 +227,16 @@ private function getMethodParameter($parameterIndex, ReflectionParameter $parame return null; } - // Try to use the type-hinting + // Look for the property type $parameterType = $parameter->getType(); if ($parameterType && !$parameterType->isBuiltin() && $parameterType instanceof ReflectionNamedType) { return $parameterType->getName(); } - // Last resort, look for @param tag - return $this->getPhpDocReader()->getParameterClass($parameter); + return null; } - /** - * @return Reader The annotation reader - */ - public function getAnnotationReader() + public function getAnnotationReader(): Reader { if ($this->annotationReader === null) { AnnotationRegistry::registerLoader('class_exists'); @@ -261,17 +248,8 @@ public function getAnnotationReader() } /** - * @return PhpDocReader + * @throws InvalidAnnotation */ - private function getPhpDocReader() - { - if ($this->phpDocReader === null) { - $this->phpDocReader = new PhpDocReader($this->ignorePhpDocErrors); - } - - return $this->phpDocReader; - } - private function readInjectableAnnotation(ReflectionClass $class, ObjectDefinition $definition) { try { diff --git a/src/Invoker/FactoryParameterResolver.php b/src/Invoker/FactoryParameterResolver.php index 9ca11ce23..ee87e28df 100644 --- a/src/Invoker/FactoryParameterResolver.php +++ b/src/Invoker/FactoryParameterResolver.php @@ -7,6 +7,7 @@ use Invoker\ParameterResolver\ParameterResolver; use Psr\Container\ContainerInterface; use ReflectionFunctionAbstract; +use ReflectionNamedType; /** * Inject the container, the definition or any other service using type-hints. diff --git a/tests/IntegrationTest/Annotations/AnnotationsTest.php b/tests/IntegrationTest/Annotations/AnnotationsTest.php index 0e4e6e848..72caebcdc 100644 --- a/tests/IntegrationTest/Annotations/AnnotationsTest.php +++ b/tests/IntegrationTest/Annotations/AnnotationsTest.php @@ -102,37 +102,4 @@ public function errors_if_dependency_by_name_not_found(ContainerBuilder $builder $builder->useAnnotations(true); $builder->build()->get(NamedInjection::class); } - - /** - * Check that @ var annotation takes "use" statements into account. - * @test - * @dataProvider provideContainer - * @link https://github.com/PHP-DI/PHP-DI/issues/1 - */ - public function resolve_class_names_using_import_statements(ContainerBuilder $builder) - { - $builder->useAnnotations(true); - $container = $builder->build(); - - /** @var $object InjectWithUseStatements */ - $object = $container->get(InjectWithUseStatements::class); - $this->assertInstanceOf(A::class, $object->a); - $this->assertInstanceOf(A::class, $object->alias); - $this->assertInstanceOf(A::class, $object->namespaceAlias); - - /** @var $object InjectWithUseStatements2 */ - $object = $container->get(InjectWithUseStatements2::class); - $this->assertInstanceOf(InjectWithUseStatements::class, $object->dependency); - } - - /** - * @test - * @dataProvider provideContainer - */ - public function testNotFoundVarAnnotation(ContainerBuilder $builder) - { - $this->expectException('PhpDocReader\AnnotationException'); - $builder->useAnnotations(true); - $builder->build()->get(NotFoundVarAnnotation::class); - } } diff --git a/tests/IntegrationTest/Annotations/B.php b/tests/IntegrationTest/Annotations/B.php index 41f25fe1e..05aa88694 100644 --- a/tests/IntegrationTest/Annotations/B.php +++ b/tests/IntegrationTest/Annotations/B.php @@ -10,21 +10,18 @@ class B { /** * @Inject - * @var A */ - public $public; + public A $public; /** * @Inject - * @var A */ - protected $protected; + protected A $protected; /** * @Inject - * @var A */ - private $private; + private A $private; public function getProtected() { diff --git a/tests/IntegrationTest/Annotations/Child.php b/tests/IntegrationTest/Annotations/Child.php index 2764446a5..fd5245096 100644 --- a/tests/IntegrationTest/Annotations/Child.php +++ b/tests/IntegrationTest/Annotations/Child.php @@ -10,9 +10,8 @@ class Child extends B { /** * @Inject - * @var A */ - private $private; + private A $private; public function getChildPrivate() { diff --git a/tests/IntegrationTest/Annotations/InjectWithUseStatements.php b/tests/IntegrationTest/Annotations/InjectWithUseStatements.php deleted file mode 100644 index 0c71b3061..000000000 --- a/tests/IntegrationTest/Annotations/InjectWithUseStatements.php +++ /dev/null @@ -1,30 +0,0 @@ -assertRegExp('/^Object \(\n {4}class = DI\\\Container\n/', $container->debugEntry('DI\Container')); - $this->assertRegExp( + $this->assertMatchesRegularExpression('/^Object \(\n {4}class = DI\\\Container\n/', $container->debugEntry('DI\Container')); + $this->assertMatchesRegularExpression( '/^Object \(\n {4}class = #NOT INSTANTIABLE# DI\\\FactoryInterface\n/', $container->debugEntry('DI\FactoryInterface') ); - $this->assertRegExp( + $this->assertMatchesRegularExpression( '/^Object \(\n {4}class = #NOT INSTANTIABLE# Invoker\\\InvokerInterface\n/', $container->debugEntry('Invoker\InvokerInterface') ); - $this->assertRegExp( + $this->assertMatchesRegularExpression( '/^Object \(\n {4}class = #NOT INSTANTIABLE# Psr\\\Container\\\ContainerInterface\n/', $container->debugEntry('Psr\Container\ContainerInterface') ); // Container definitions - $this->assertRegExp('/^Object \(\n {4}class = DI\\\Container\n/', $container->debugEntry('create')); - $this->assertRegExp('/^Object \(\n {4}class = DI\\\Container\n/', $container->debugEntry('autowire')); + $this->assertMatchesRegularExpression('/^Object \(\n {4}class = DI\\\Container\n/', $container->debugEntry('create')); + $this->assertMatchesRegularExpression('/^Object \(\n {4}class = DI\\\Container\n/', $container->debugEntry('autowire')); $this->assertEquals('Factory', $container->debugEntry('factory')); $this->assertEquals('Factory', $container->debugEntry('callback')); $this->assertEquals('Decorate(decorator)', $container->debugEntry('decorator')); $this->assertEquals('get(value)', $container->debugEntry('alias')); - $this->assertRegExp('/^Environment variable \(\n {4}variable = foo\n/', $container->debugEntry('environment')); + $this->assertMatchesRegularExpression('/^Environment variable \(\n {4}variable = foo\n/', $container->debugEntry('environment')); $this->assertEquals("[\n 0 => 'foo',\n 1 => 'bar',\n]", $container->debugEntry('array')); $this->assertEquals('foo', $container->debugEntry('string')); $this->assertEquals('Value (1.5)', $container->debugEntry('float')); diff --git a/tests/IntegrationTest/ContainerInjectOnTest.php b/tests/IntegrationTest/ContainerInjectOnTest.php index f322905a6..38913429e 100644 --- a/tests/IntegrationTest/ContainerInjectOnTest.php +++ b/tests/IntegrationTest/ContainerInjectOnTest.php @@ -164,9 +164,8 @@ public function testInjectOnAnonClass(ContainerBuilder $builder) $obj = new class { /** * @Inject - * @var Class2 */ - public $property; + public Class2 $property; public $methodParam; diff --git a/tests/IntegrationTest/Definitions/AnnotationTest.php b/tests/IntegrationTest/Definitions/AnnotationTest.php index 7bcb852f6..c831760cd 100644 --- a/tests/IntegrationTest/Definitions/AnnotationTest.php +++ b/tests/IntegrationTest/Definitions/AnnotationTest.php @@ -42,7 +42,6 @@ public function test_constructor_injection(ContainerBuilder $builder) $object = $container->get(ConstructorInjection::class); self::assertEquals(new \stdClass, $object->typedValue); - self::assertEquals(new \stdClass, $object->untypedValue); self::assertEquals(new \stdClass, $object->typedOptionalValue); self::assertEquals('bar', $object->value); self::assertInstanceOf(\stdClass::class, $object->lazyService); @@ -68,7 +67,6 @@ public function test_property_injection(ContainerBuilder $builder) self::assertEquals('bar', $object->value); self::assertEquals('bar', $object->value2); self::assertInstanceOf(\stdClass::class, $object->entry); - self::assertInstanceOf(NamespacedClass::class, $object->importedNamespace); self::assertInstanceOf(\stdClass::class, $object->lazyService); self::assertInstanceOf(LazyLoadingInterface::class, $object->lazyService); self::assertFalse($object->lazyService->isProxyInitialized()); @@ -89,7 +87,6 @@ public function test_method_injection(ContainerBuilder $builder) $object = $container->get(ConstructorInjection::class); self::assertEquals(new \stdClass, $object->typedValue); - self::assertEquals(new \stdClass, $object->untypedValue); self::assertEquals(new \stdClass, $object->typedOptionalValue); self::assertEquals('bar', $object->value); self::assertInstanceOf(\stdClass::class, $object->lazyService); @@ -102,6 +99,7 @@ public function test_method_injection(ContainerBuilder $builder) namespace DI\Test\IntegrationTest\Definitions\AnnotationTest; use DI\Annotation\Inject; +use stdClass; class NonAnnotatedClass { @@ -116,7 +114,6 @@ class ConstructorInjection public $value; public $scalarValue; public $typedValue; - public $untypedValue; public $typedOptionalValue; /** @var \ProxyManager\Proxy\LazyLoadingInterface */ public $lazyService; @@ -124,13 +121,11 @@ class ConstructorInjection /** * @Inject({"value" = "foo", "scalarValue" = "foo", "lazyService" = "lazyService"}) - * @param \stdClass $untypedValue */ public function __construct( $value, string $scalarValue, \stdClass $typedValue, - $untypedValue, \stdClass $typedOptionalValue = null, \stdClass $lazyService, $optionalValue = 'hello' @@ -138,7 +133,6 @@ public function __construct( $this->value = $value; $this->scalarValue = $scalarValue; $this->typedValue = $typedValue; - $this->untypedValue = $untypedValue; $this->typedOptionalValue = $typedOptionalValue; $this->lazyService = $lazyService; $this->optionalValue = $optionalValue; @@ -157,14 +151,8 @@ class PropertyInjection public $value2; /** * @Inject - * @var \stdClass */ - public $entry; - /** - * @Inject - * @var NamespacedClass - */ - public $importedNamespace; + public stdClass $entry; /** * @Inject("lazyService") */ @@ -176,7 +164,6 @@ class MethodInjection public $value; public $scalarValue; public $typedValue; - public $untypedValue; public $typedOptionalValue; /** @var \ProxyManager\Proxy\LazyLoadingInterface */ public $lazyService; @@ -184,12 +171,10 @@ class MethodInjection /** * @Inject({"value" = "foo", "scalarValue" = "foo", "lazyService" = "lazyService"}) - * @param \stdClass $untypedValue */ public function method( $value, string $scalarValue, - \stdClass $typedValue, $untypedValue, \stdClass $typedOptionalValue = null, \stdClass $lazyService, @@ -197,7 +182,6 @@ public function method( ) { $this->value = $value; $this->scalarValue = $scalarValue; - $this->typedValue = $typedValue; $this->untypedValue = $untypedValue; $this->typedOptionalValue = $typedOptionalValue; $this->lazyService = $lazyService; diff --git a/tests/IntegrationTest/Definitions/WildcardDefinitionsTest.php b/tests/IntegrationTest/Definitions/WildcardDefinitionsTest.php index 80d1a6d85..5685282f6 100644 --- a/tests/IntegrationTest/Definitions/WildcardDefinitionsTest.php +++ b/tests/IntegrationTest/Definitions/WildcardDefinitionsTest.php @@ -115,7 +115,6 @@ class WildcardDefinitionsTestFixture { /** * @Inject - * @var Interface1 */ - public $dependency; + public Interface1 $dependency; } diff --git a/tests/IntegrationTest/Fixtures/Class1.php b/tests/IntegrationTest/Fixtures/Class1.php index ca96d46ad..b72b2ebae 100644 --- a/tests/IntegrationTest/Fixtures/Class1.php +++ b/tests/IntegrationTest/Fixtures/Class1.php @@ -15,15 +15,13 @@ class Class1 { /** * @Inject - * @var Class2 */ - public $property1; + public Class2 $property1; /** * @Inject - * @var Interface1 */ - public $property2; + public Interface1 $property2; /** * @Inject("namedDependency") @@ -37,9 +35,8 @@ class Class1 /** * @Inject - * @var LazyDependency */ - public $property5; + public LazyDependency $property5; public $constructorParam1; public $constructorParam2; @@ -55,9 +52,6 @@ class Class1 public $method4Param1; /** - * @param Class2 $param1 - * @param Interface1 $param2 - * @param LazyDependency $param3 * @throws \Exception */ public function __construct(Class2 $param1, Interface1 $param2, LazyDependency $param3, $optional = true) diff --git a/tests/IntegrationTest/Fixtures/InheritanceTest/BaseClass.php b/tests/IntegrationTest/Fixtures/InheritanceTest/BaseClass.php index 9f2f2838c..cbb825e43 100644 --- a/tests/IntegrationTest/Fixtures/InheritanceTest/BaseClass.php +++ b/tests/IntegrationTest/Fixtures/InheritanceTest/BaseClass.php @@ -13,23 +13,13 @@ abstract class BaseClass { /** * @Inject - * @var Dependency */ - public $property1; + public Dependency $property1; - /** - * @var Dependency - */ - public $property2; + public Dependency $property2; - /** - * @var Dependency - */ - public $property3; + public Dependency $property3; - /** - * @param Dependency $param1 - */ public function __construct(Dependency $param1) { $this->property3 = $param1; @@ -37,7 +27,6 @@ public function __construct(Dependency $param1) /** * @Inject - * @param Dependency $property2 */ public function setProperty2(Dependency $property2) { diff --git a/tests/IntegrationTest/Fixtures/InheritanceTest/Dependency.php b/tests/IntegrationTest/Fixtures/InheritanceTest/Dependency.php index f7accb3c5..a9529709f 100644 --- a/tests/IntegrationTest/Fixtures/InheritanceTest/Dependency.php +++ b/tests/IntegrationTest/Fixtures/InheritanceTest/Dependency.php @@ -9,10 +9,7 @@ */ class Dependency { - /** - * @return bool - */ - public function getBoolean() + public function getBoolean(): bool { return true; } diff --git a/tests/IntegrationTest/Fixtures/InheritanceTest/SubClass.php b/tests/IntegrationTest/Fixtures/InheritanceTest/SubClass.php index 83c416950..ebfad0543 100644 --- a/tests/IntegrationTest/Fixtures/InheritanceTest/SubClass.php +++ b/tests/IntegrationTest/Fixtures/InheritanceTest/SubClass.php @@ -13,7 +13,6 @@ class SubClass extends BaseClass { /** * @Inject - * @var Dependency */ - public $property4; + public Dependency $property4; } diff --git a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php b/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php index 00af08b19..e8e0a1878 100644 --- a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php +++ b/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php @@ -20,6 +20,7 @@ use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixtureTypedProperties; use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationInjectableFixture; use PHPUnit\Framework\TestCase; +use DI\Definition\Exception\InvalidAnnotation; /** * @covers \DI\Definition\Source\AnnotationBasedAutowiring @@ -60,22 +61,17 @@ public function testStaticProperty() public function testUnguessableProperty() { - $this->expectException('DI\Definition\Exception\InvalidAnnotation'); - $this->expectExceptionMessage('@Inject found on property DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture4::property but unable to guess what to inject, use a @var annotation'); + $this->expectException(InvalidAnnotation::class); + $this->expectExceptionMessage('@Inject found on property DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture4::property but unable to guess what to inject, please add a type to the property'); (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'); } @@ -137,11 +133,10 @@ public function testMethod3() $this->assertInstanceOf(MethodInjection::class, $methodInjection); $parameters = $methodInjection->getParameters(); - $this->assertCount(2, $parameters); + $this->assertCount(1, $parameters); $reference = new Reference(AnnotationFixture2::class); $this->assertEquals($reference, $parameters[0]); - $this->assertEquals($reference, $parameters[1]); } public function testMethod4() @@ -210,10 +205,7 @@ public function testInjectable() $this->assertTrue($definition->isLazy()); } - /** - * @see https://github.com/mnapoli/PHP-DI/issues/99 - */ - public function testIssue99() + public function test_method_injection_with_primitive_type_causes_an_error() { $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture3::class); $this->assertInstanceOf(Definition::class, $definition); @@ -229,24 +221,13 @@ public function testIssue99() ); } - /** - * @see https://github.com/mnapoli/PHP-DI/issues/184 - */ - public function testFailWithPhpDocErrors() + public function testFailWithTypeError() { - $this->expectException('PhpDocReader\AnnotationException'); + $this->expectException(InvalidAnnotation::class); + $this->expectExceptionMessage('@Inject found on property DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture5::property but unable to guess what to inject, the type of the property does not look like a valid class or interface name'); (new AnnotationBasedAutowiring)->autowire(AnnotationFixture5::class); } - /** - * @see https://github.com/mnapoli/PHP-DI/issues/184 - */ - public function testIgnorePhpDocErrors() - { - $source = new AnnotationBasedAutowiring($ignorePhpDocErrors = true); - $source->autowire(AnnotationFixture5::class); - } - public function testMergedWithParentDefinition() { $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureChild::class); diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture.php index 06a961a80..0ae309373 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture.php @@ -15,9 +15,8 @@ class AnnotationFixture /** * @Inject - * @var AnnotationFixture2 */ - protected $property2; + protected AnnotationFixture2 $property2; /** * @Inject(name="foo") @@ -57,9 +56,8 @@ public function method2($param1, $param2) /** * @Inject * @param $param1 - * @param AnnotationFixture2 $param2 */ - public function method3(AnnotationFixture2 $param1, $param2) + public function method3(AnnotationFixture2 $param1) { } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture3.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture3.php index 2bb52dfce..437c3bef9 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture3.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture3.php @@ -8,10 +8,8 @@ class AnnotationFixture3 { /** * @Inject - * @param AnnotationFixture2 $param1 - * @param string $param2 */ - public function method1($param1, $param2) + public function method1(AnnotationFixture2 $param1, bool $param2) { } } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture5.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture5.php index 8e1e53b74..64d72a862 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture5.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture5.php @@ -8,14 +8,10 @@ class AnnotationFixture5 { /** * @Inject - * @var foobar */ - public $property; + public foobar $property; - /** - * @param foobar $foo - */ - public function __construct($foo) + public function __construct(foobar $foo) { } } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureTypedProperties.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureTypedProperties.php index 24a6702c5..8bde283fe 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureTypedProperties.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureTypedProperties.php @@ -13,12 +13,6 @@ class AnnotationFixtureTypedProperties */ protected AnnotationFixture2 $typedAndInject; - /** - * @Inject - * @var AnnotationFixture3 - */ - protected AnnotationFixture2 $typedAndVar; - /** * @Inject("name") */ diff --git a/tests/UnitTest/Fixtures/Class1CircularDependencies.php b/tests/UnitTest/Fixtures/Class1CircularDependencies.php index 41e691b24..75f77dfa1 100644 --- a/tests/UnitTest/Fixtures/Class1CircularDependencies.php +++ b/tests/UnitTest/Fixtures/Class1CircularDependencies.php @@ -11,7 +11,6 @@ class Class1CircularDependencies { /** * @Inject - * @var \DI\Test\UnitTest\Fixtures\Class2CircularDependencies */ - public $class2; + public Class2CircularDependencies $class2; } diff --git a/tests/UnitTest/Fixtures/Class2CircularDependencies.php b/tests/UnitTest/Fixtures/Class2CircularDependencies.php index cead137dc..c82d919a9 100644 --- a/tests/UnitTest/Fixtures/Class2CircularDependencies.php +++ b/tests/UnitTest/Fixtures/Class2CircularDependencies.php @@ -11,7 +11,7 @@ class Class2CircularDependencies { /** * @Inject - * @var \DI\Test\UnitTest\Fixtures\Class1CircularDependencies + * @var Class1CircularDependencies */ - public $class1; + public Class1CircularDependencies $class1; } From dde46274906dc206c801286502dc10ab8c60dce4 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 1 Aug 2020 22:39:15 +0200 Subject: [PATCH 02/45] Remove the obsolete `ignorePhpDocErrors` option --- doc/container-configuration.md | 32 -------------------------------- src/ContainerBuilder.php | 21 +-------------------- 2 files changed, 1 insertion(+), 52 deletions(-) diff --git a/doc/container-configuration.md b/doc/container-configuration.md index d1637b675..f8a5ebced 100644 --- a/doc/container-configuration.md +++ b/doc/container-configuration.md @@ -78,35 +78,3 @@ $container->addContainer($phpdiContainer); // Good to go! $foo = $container->get('foo'); ``` - -## Ignoring phpDoc errors - -*Added in v4.4* - -If you use annotations and your phpDoc is not always correct, you can set up the container to silently ignore those errors: - -```php -$builder->ignorePhpDocErrors(true); -``` - -For example: - -```php -class Foo -{ - /** - * @param NonExistentClass $param - */ - public function useAutowiring($param) - { - } -} -``` - -Here, PHP-DI will throw an exception because `NonExistentClass` doesn't exist: this is a phpDoc error. - -There has been reports that PHP-FPM might choke on such errors and report it with a message like this: - -> Handler for fastcgi-script returned invalid result code 1 - -In case the errors still occur, make sure your annotations are correct or temporarily disable annotations (`$builder->useAnnotations(false)`) to prevent fatal errors and try to clean up your configuration form there. diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index 3ee747f43..32a7992a3 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -56,11 +56,6 @@ class ContainerBuilder */ private $useAnnotations = false; - /** - * @var bool - */ - private $ignorePhpDocErrors = false; - /** * If true, write the proxies to disk to improve performances. * @var bool @@ -131,7 +126,7 @@ public function build() $sources = array_reverse($this->definitionSources); if ($this->useAnnotations) { - $autowiring = new AnnotationBasedAutowiring($this->ignorePhpDocErrors); + $autowiring = new AnnotationBasedAutowiring; $sources[] = $autowiring; } elseif ($this->useAutowiring) { $autowiring = new ReflectionBasedAutowiring; @@ -253,20 +248,6 @@ public function useAnnotations(bool $bool) : self return $this; } - /** - * Enable or disable ignoring phpdoc errors (non-existent classes in `@param` or `@var`). - * - * @return $this - */ - public function ignorePhpDocErrors(bool $bool) : self - { - $this->ensureNotLocked(); - - $this->ignorePhpDocErrors = $bool; - - return $this; - } - /** * Configure the proxy generation. * From 0f3b69fdc610df79a70b29d5328091cde345a855 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 1 Aug 2020 22:41:13 +0200 Subject: [PATCH 03/45] Fix code formatting --- src/Definition/Source/AnnotationBasedAutowiring.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Definition/Source/AnnotationBasedAutowiring.php b/src/Definition/Source/AnnotationBasedAutowiring.php index c4fca7f4e..4fa9f5fda 100644 --- a/src/Definition/Source/AnnotationBasedAutowiring.php +++ b/src/Definition/Source/AnnotationBasedAutowiring.php @@ -170,7 +170,7 @@ private function readMethods(ReflectionClass $class, ObjectDefinition $objectDef /** * @throws InvalidAnnotation */ - private function getMethodInjection(ReflectionMethod $method): ?MethodInjection + private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection { // Look for @Inject annotation try { @@ -236,7 +236,7 @@ private function getMethodParameter($parameterIndex, ReflectionParameter $parame return null; } - public function getAnnotationReader(): Reader + public function getAnnotationReader() : Reader { if ($this->annotationReader === null) { AnnotationRegistry::registerLoader('class_exists'); From 15afdada9a37335b1ba621169f3e3e1f7b80831f Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 1 Aug 2020 23:16:03 +0200 Subject: [PATCH 04/45] Improve type declarations following the PHP 7.4 requirement --- src/Annotation/Inject.php | 8 +-- src/Annotation/Injectable.php | 8 +-- src/CompiledContainer.php | 11 ++-- src/Compiler/Compiler.php | 40 ++++--------- src/Compiler/ObjectCreationCompiler.php | 9 +-- src/Compiler/RequestedEntryHolder.php | 5 +- src/Container.php | 54 +++++------------- src/ContainerBuilder.php | 50 +++++------------ src/Definition/ArrayDefinition.php | 12 ++-- src/Definition/ArrayDefinitionExtension.php | 7 +-- src/Definition/DecoratorDefinition.php | 14 ++--- src/Definition/Definition.php | 4 +- .../EnvironmentVariableDefinition.php | 14 ++--- src/Definition/ExtendsPreviousDefinition.php | 2 +- src/Definition/FactoryDefinition.php | 9 ++- .../Helper/AutowireDefinitionHelper.php | 6 +- .../Helper/CreateDefinitionHelper.php | 36 ++++-------- .../Helper/FactoryDefinitionHelper.php | 18 ++---- src/Definition/InstanceDefinition.php | 23 ++------ src/Definition/ObjectDefinition.php | 56 ++++++------------- .../ObjectDefinition/MethodInjection.php | 11 ++-- .../ObjectDefinition/PropertyInjection.php | 16 ++---- src/Definition/Reference.php | 10 ++-- src/Definition/Resolver/ArrayResolver.php | 5 +- src/Definition/Resolver/DecoratorResolver.php | 10 +--- .../Resolver/EnvironmentVariableResolver.php | 5 +- src/Definition/Resolver/FactoryResolver.php | 15 +---- src/Definition/Resolver/InstanceInjector.php | 2 +- src/Definition/Resolver/ObjectCreator.php | 33 ++++------- src/Definition/Resolver/ParameterResolver.php | 5 +- .../Resolver/ResolverDispatcher.php | 24 +++----- src/Definition/StringDefinition.php | 12 ++-- src/Definition/ValueDefinition.php | 7 +-- src/FactoryInterface.php | 2 +- src/Invoker/DefinitionParameterResolver.php | 5 +- src/Invoker/FactoryParameterResolver.php | 5 +- src/Proxy/ProxyFactory.php | 15 ++--- src/functions.php | 4 +- .../IntegrationTest/ContainerInjectOnTest.php | 8 --- tests/IntegrationTest/ContainerMakeTest.php | 10 ---- 40 files changed, 176 insertions(+), 414 deletions(-) diff --git a/src/Annotation/Inject.php b/src/Annotation/Inject.php index c0eef199d..dc69d646a 100644 --- a/src/Annotation/Inject.php +++ b/src/Annotation/Inject.php @@ -22,17 +22,15 @@ final class Inject { /** * Entry name. - * @var string */ - private $name; + private ?string $name = null; /** * Parameters, indexed by the parameter number (index) or name. * * Used if the annotation is set on a method - * @var array */ - private $parameters = []; + private array $parameters = []; /** * @throws InvalidAnnotation @@ -78,7 +76,7 @@ public function __construct(array $values) /** * @return string|null Name of the entry to inject */ - public function getName() + public function getName() : ?string { return $this->name; } diff --git a/src/Annotation/Injectable.php b/src/Annotation/Injectable.php index ea159449c..96e4b69f2 100644 --- a/src/Annotation/Injectable.php +++ b/src/Annotation/Injectable.php @@ -21,9 +21,8 @@ final class Injectable { /** * Should the object be lazy-loaded. - * @var bool|null */ - private $lazy; + private ?bool $lazy = null; public function __construct(array $values) { @@ -32,10 +31,7 @@ public function __construct(array $values) } } - /** - * @return bool|null - */ - public function isLazy() + public function isLazy() : ?bool { return $this->lazy; } diff --git a/src/CompiledContainer.php b/src/CompiledContainer.php index 88438d736..b80ec226a 100644 --- a/src/CompiledContainer.php +++ b/src/CompiledContainer.php @@ -24,10 +24,7 @@ */ abstract class CompiledContainer extends Container { - /** - * @var InvokerInterface - */ - private $factoryInvoker; + private ?InvokerInterface $factoryInvoker = null; /** * {@inheritdoc} @@ -67,7 +64,7 @@ public function get($name) /** * {@inheritdoc} */ - public function has($name) + public function has($name): bool { if (! is_string($name)) { throw new \InvalidArgumentException(sprintf( @@ -84,7 +81,7 @@ public function has($name) return parent::has($name); } - protected function setDefinition(string $name, Definition $definition) + protected function setDefinition(string $name, Definition $definition): void { // It needs to be forbidden because that would mean get() must go through the definitions // every time, which kinds of defeats the performance gains of the compiled container @@ -93,6 +90,8 @@ protected function setDefinition(string $name, Definition $definition) /** * Invoke the given callable. + * + * @return mixed */ protected function resolveFactory($callable, $entryName, array $extraParameters = []) { diff --git a/src/Compiler/Compiler.php b/src/Compiler/Compiler.php index db6fe9694..c40aaf484 100644 --- a/src/Compiler/Compiler.php +++ b/src/Compiler/Compiler.php @@ -27,24 +27,16 @@ */ class Compiler { - /** - * @var string - */ - private $containerClass; + private string $containerClass; - /** - * @var string - */ - private $containerParentClass; + private string $containerParentClass; /** * Definitions indexed by the entry name. The value can be null if the definition needs to be fetched. * * Keys are strings, values are `Definition` objects or null. - * - * @var \ArrayIterator */ - private $entriesToCompile; + private \ArrayIterator $entriesToCompile; /** * Progressive counter for definitions. @@ -52,10 +44,8 @@ class Compiler * Each key in $entriesToCompile is defined as 'SubEntry' + counter * and each definition has always the same key in the CompiledContainer * if PHP-DI configuration does not change. - * - * @var int */ - private $subEntryCounter; + private int $subEntryCounter = 0; /** * Progressive counter for CompiledContainer get methods. @@ -63,32 +53,24 @@ class Compiler * Each CompiledContainer method name is defined as 'get' + counter * and remains the same after each recompilation * if PHP-DI configuration does not change. - * - * @var int */ - private $methodMappingCounter; + private int $methodMappingCounter = 0; /** * Map of entry names to method names. * * @var string[] */ - private $entryToMethodMapping = []; + private array $entryToMethodMapping = []; /** * @var string[] */ - private $methods = []; + private array $methods = []; - /** - * @var bool - */ - private $autowiringEnabled; + private bool $autowiringEnabled; - /** - * @var ProxyFactory - */ - private $proxyFactory; + private ProxyFactory $proxyFactory; public function __construct(ProxyFactory $proxyFactory) { @@ -323,7 +305,7 @@ public function compileValue($value) : string return var_export($value, true); } - private function createCompilationDirectory(string $directory) + private function createCompilationDirectory(string $directory) : void { if (!is_dir($directory) && !@mkdir($directory, 0777, true)) { throw new InvalidArgumentException(sprintf('Compilation directory does not exist and cannot be created: %s.', $directory)); @@ -364,7 +346,7 @@ private function isCompilable($value) } /** - * @throws \DI\Definition\Exception\InvalidDefinition + * @throws InvalidDefinition */ private function compileClosure(\Closure $closure) : string { diff --git a/src/Compiler/ObjectCreationCompiler.php b/src/Compiler/ObjectCreationCompiler.php index 9f19d4c00..138cb2d34 100644 --- a/src/Compiler/ObjectCreationCompiler.php +++ b/src/Compiler/ObjectCreationCompiler.php @@ -19,10 +19,7 @@ */ class ObjectCreationCompiler { - /** - * @var Compiler - */ - private $compiler; + private Compiler $compiler; public function __construct(Compiler $compiler) { @@ -176,7 +173,7 @@ private function getFunctionName(ReflectionMethod $method) : string return $method->getName() . '()'; } - private function assertClassIsNotAnonymous(ObjectDefinition $definition) + private function assertClassIsNotAnonymous(ObjectDefinition $definition) : void { if (strpos($definition->getClassName(), '@') !== false) { throw InvalidDefinition::create($definition, sprintf( @@ -186,7 +183,7 @@ private function assertClassIsNotAnonymous(ObjectDefinition $definition) } } - private function assertClassIsInstantiable(ObjectDefinition $definition) + private function assertClassIsInstantiable(ObjectDefinition $definition) : void { if ($definition->isInstantiable()) { return; diff --git a/src/Compiler/RequestedEntryHolder.php b/src/Compiler/RequestedEntryHolder.php index 68b5bc2dc..a84cddf40 100644 --- a/src/Compiler/RequestedEntryHolder.php +++ b/src/Compiler/RequestedEntryHolder.php @@ -11,10 +11,7 @@ */ class RequestedEntryHolder implements RequestedEntry { - /** - * @var string - */ - private $name; + private string $name; public function __construct(string $name) { diff --git a/src/Container.php b/src/Container.php index c3a33ee72..7f8f0aba2 100644 --- a/src/Container.php +++ b/src/Container.php @@ -40,49 +40,33 @@ class Container implements ContainerInterface, FactoryInterface, InvokerInterfac { /** * Map of entries that are already resolved. - * @var array */ - protected $resolvedEntries = []; + protected array $resolvedEntries = []; - /** - * @var MutableDefinitionSource - */ - private $definitionSource; + private MutableDefinitionSource $definitionSource; - /** - * @var DefinitionResolver - */ - private $definitionResolver; + private DefinitionResolver $definitionResolver; /** * Map of definitions that are already fetched (local cache). * - * @var (Definition|null)[] + * @var array */ - private $fetchedDefinitions = []; + private array $fetchedDefinitions = []; /** * Array of entries being resolved. Used to avoid circular dependencies and infinite loops. - * @var array */ - protected $entriesBeingResolved = []; + protected array $entriesBeingResolved = []; - /** - * @var InvokerInterface|null - */ - private $invoker; + private ?InvokerInterface $invoker = null; /** * Container that wraps this container. If none, points to $this. - * - * @var ContainerInterface */ - protected $delegateContainer; + protected ContainerInterface $delegateContainer; - /** - * @var ProxyFactory - */ - protected $proxyFactory; + protected ProxyFactory $proxyFactory; /** * Use `$container = new Container()` if you want a container with the default configuration. @@ -142,12 +126,7 @@ public function get($name) return $value; } - /** - * @param string $name - * - * @return Definition|null - */ - private function getDefinition($name) + private function getDefinition(string $name) : ?Definition { // Local cache that avoids fetching the same definition twice if (!array_key_exists($name, $this->fetchedDefinitions)) { @@ -175,7 +154,7 @@ private function getDefinition($name) * @throws NotFoundException No entry found for the given name. * @return mixed */ - public function make($name, array $parameters = []) + public function make(string $name, array $parameters = []) { if (! is_string($name)) { throw new InvalidArgumentException(sprintf( @@ -203,9 +182,8 @@ public function make($name, array $parameters = []) * @param string $name Entry name or a class name. * * @throws InvalidArgumentException The name parameter must be of type string. - * @return bool */ - public function has($name) + public function has($name): bool { if (! is_string($name)) { throw new InvalidArgumentException(sprintf( @@ -234,12 +212,8 @@ public function has($name) * @throws DependencyException Error while injecting dependencies * @return object $instance Returns the same instance */ - public function injectOn($instance) + public function injectOn(object $instance): object { - if (!$instance) { - return $instance; - } - $className = get_class($instance); // If the class is anonymous, don't cache its definition @@ -392,7 +366,7 @@ private function resolveDefinition(Definition $definition, array $parameters = [ return $value; } - protected function setDefinition(string $name, Definition $definition) + protected function setDefinition(string $name, Definition $definition) : void { // Clear existing entry if it exists if (array_key_exists($name, $this->resolvedEntries)) { diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index 32a7992a3..56d34dcf0 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -36,69 +36,48 @@ class ContainerBuilder { /** * Name of the container class, used to create the container. - * @var string */ - private $containerClass; + private string $containerClass; /** * Name of the container parent class, used on compiled container. - * @var string */ - private $containerParentClass; + private string $containerParentClass; - /** - * @var bool - */ - private $useAutowiring = true; + private bool $useAutowiring = true; - /** - * @var bool - */ - private $useAnnotations = false; + private bool $useAnnotations = false; /** * If true, write the proxies to disk to improve performances. - * @var bool */ - private $writeProxiesToFile = false; + private bool $writeProxiesToFile = false; /** * Directory where to write the proxies (if $writeProxiesToFile is enabled). - * @var string|null */ - private $proxyDirectory; + private ?string $proxyDirectory = null; /** * If PHP-DI is wrapped in another container, this references the wrapper. - * @var ContainerInterface */ - private $wrapperContainer; + private ?ContainerInterface $wrapperContainer = null; /** * @var DefinitionSource[]|string[]|array[] */ - private $definitionSources = []; + private array $definitionSources = []; /** * Whether the container has already been built. - * @var bool */ - private $locked = false; + private bool $locked = false; - /** - * @var string|null - */ - private $compileToDirectory; + private ?string $compileToDirectory = null; - /** - * @var bool - */ - private $sourceCache = false; + private bool $sourceCache = false; - /** - * @var string - */ - protected $sourceCacheNamespace; + protected string $sourceCacheNamespace = ''; /** * Build a container configured for the dev environment. @@ -139,7 +118,8 @@ public function build() if (is_string($definitions)) { // File return new DefinitionFile($definitions, $autowiring); - } elseif (is_array($definitions)) { + } + if (is_array($definitions)) { return new DefinitionArray($definitions, $autowiring); } @@ -357,7 +337,7 @@ public function isCompilationEnabled() : bool return (bool) $this->compileToDirectory; } - private function ensureNotLocked() + private function ensureNotLocked(): void { if ($this->locked) { throw new \LogicException('The ContainerBuilder cannot be modified after the container has been built'); diff --git a/src/Definition/ArrayDefinition.php b/src/Definition/ArrayDefinition.php index 8b06fed6d..db1b1f018 100644 --- a/src/Definition/ArrayDefinition.php +++ b/src/Definition/ArrayDefinition.php @@ -14,14 +14,10 @@ class ArrayDefinition implements Definition { /** * Entry name. - * @var string */ - private $name = ''; + private string $name = ''; - /** - * @var array - */ - private $values; + private array $values; public function __construct(array $values) { @@ -33,7 +29,7 @@ public function getName() : string return $this->name; } - public function setName(string $name) + public function setName(string $name) : void { $this->name = $name; } @@ -43,7 +39,7 @@ public function getValues() : array return $this->values; } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { $this->values = array_map($replacer, $this->values); } diff --git a/src/Definition/ArrayDefinitionExtension.php b/src/Definition/ArrayDefinitionExtension.php index b49487332..d55f12488 100644 --- a/src/Definition/ArrayDefinitionExtension.php +++ b/src/Definition/ArrayDefinitionExtension.php @@ -14,10 +14,7 @@ */ class ArrayDefinitionExtension extends ArrayDefinition implements ExtendsPreviousDefinition { - /** - * @var ArrayDefinition - */ - private $subDefinition; + private ?ArrayDefinition $subDefinition = null; public function getValues() : array { @@ -28,7 +25,7 @@ public function getValues() : array return array_merge($this->subDefinition->getValues(), parent::getValues()); } - public function setExtendedDefinition(Definition $definition) + public function setExtendedDefinition(Definition $definition) : void { if (! $definition instanceof ArrayDefinition) { throw new InvalidDefinition(sprintf( diff --git a/src/Definition/DecoratorDefinition.php b/src/Definition/DecoratorDefinition.php index 44894855b..32d859977 100644 --- a/src/Definition/DecoratorDefinition.php +++ b/src/Definition/DecoratorDefinition.php @@ -12,25 +12,19 @@ */ class DecoratorDefinition extends FactoryDefinition implements Definition, ExtendsPreviousDefinition { - /** - * @var Definition|null - */ - private $decorated; + private ?Definition $decorated = null; - public function setExtendedDefinition(Definition $definition) + public function setExtendedDefinition(Definition $definition) : void { $this->decorated = $definition; } - /** - * @return Definition|null - */ - public function getDecoratedDefinition() + public function getDecoratedDefinition() : ?Definition { return $this->decorated; } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { // no nested definitions } diff --git a/src/Definition/Definition.php b/src/Definition/Definition.php index 696838dc2..5cf4caa1f 100644 --- a/src/Definition/Definition.php +++ b/src/Definition/Definition.php @@ -23,12 +23,12 @@ public function getName() : string; /** * Set the name of the entry in the container. */ - public function setName(string $name); + public function setName(string $name) : void; /** * Apply a callable that replaces the definitions nested in this definition. */ - public function replaceNestedDefinitions(callable $replacer); + public function replaceNestedDefinitions(callable $replacer) : void; /** * Definitions can be cast to string for debugging information. diff --git a/src/Definition/EnvironmentVariableDefinition.php b/src/Definition/EnvironmentVariableDefinition.php index 73e0e2979..913c04d5d 100644 --- a/src/Definition/EnvironmentVariableDefinition.php +++ b/src/Definition/EnvironmentVariableDefinition.php @@ -14,25 +14,21 @@ class EnvironmentVariableDefinition implements Definition { /** * Entry name. - * @var string */ - private $name = ''; + private string $name = ''; /** * The name of the environment variable. - * @var string */ - private $variableName; + private string $variableName; /** * Whether or not the environment variable definition is optional. * * If true and the environment variable given by $variableName has not been * defined, $defaultValue is used. - * - * @var bool */ - private $isOptional; + private bool $isOptional; /** * The default value to use if the environment variable is optional and not provided. @@ -57,7 +53,7 @@ public function getName() : string return $this->name; } - public function setName(string $name) + public function setName(string $name) : void { $this->name = $name; } @@ -86,7 +82,7 @@ public function getDefaultValue() return $this->defaultValue; } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { $this->defaultValue = $replacer($this->defaultValue); } diff --git a/src/Definition/ExtendsPreviousDefinition.php b/src/Definition/ExtendsPreviousDefinition.php index 0b26933cb..ac2a7ab60 100644 --- a/src/Definition/ExtendsPreviousDefinition.php +++ b/src/Definition/ExtendsPreviousDefinition.php @@ -11,5 +11,5 @@ */ interface ExtendsPreviousDefinition extends Definition { - public function setExtendedDefinition(Definition $definition); + public function setExtendedDefinition(Definition $definition) : void; } diff --git a/src/Definition/FactoryDefinition.php b/src/Definition/FactoryDefinition.php index ed0936f00..47c8da734 100644 --- a/src/Definition/FactoryDefinition.php +++ b/src/Definition/FactoryDefinition.php @@ -13,9 +13,8 @@ class FactoryDefinition implements Definition { /** * Entry name. - * @var string */ - private $name; + private string $name; /** * Callable that returns the value. @@ -27,7 +26,7 @@ class FactoryDefinition implements Definition * Factory parameters. * @var mixed[] */ - private $parameters = []; + private array $parameters; /** * @param string $name Entry name @@ -46,7 +45,7 @@ public function getName() : string return $this->name; } - public function setName(string $name) + public function setName(string $name) : void { $this->name = $name; } @@ -67,7 +66,7 @@ public function getParameters() : array return $this->parameters; } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { $this->parameters = array_map($replacer, $this->parameters); } diff --git a/src/Definition/Helper/AutowireDefinitionHelper.php b/src/Definition/Helper/AutowireDefinitionHelper.php index 8dfa4e2d5..905e3f939 100644 --- a/src/Definition/Helper/AutowireDefinitionHelper.php +++ b/src/Definition/Helper/AutowireDefinitionHelper.php @@ -13,7 +13,7 @@ */ class AutowireDefinitionHelper extends CreateDefinitionHelper { - const DEFINITION_CLASS = AutowireDefinition::class; + public const DEFINITION_CLASS = AutowireDefinition::class; /** * Defines a value for a specific argument of the constructor. @@ -28,7 +28,7 @@ class AutowireDefinitionHelper extends CreateDefinitionHelper * * @return $this */ - public function constructorParameter($parameter, $value) + public function constructorParameter($parameter, $value) : self { $this->constructor[$parameter] = $value; @@ -52,7 +52,7 @@ public function constructorParameter($parameter, $value) * * @return $this */ - public function methodParameter(string $method, $parameter, $value) + public function methodParameter(string $method, $parameter, $value) : self { // Special case for the constructor if ($method === '__construct') { diff --git a/src/Definition/Helper/CreateDefinitionHelper.php b/src/Definition/Helper/CreateDefinitionHelper.php index aeae071ca..bba3a34d7 100644 --- a/src/Definition/Helper/CreateDefinitionHelper.php +++ b/src/Definition/Helper/CreateDefinitionHelper.php @@ -17,35 +17,26 @@ */ class CreateDefinitionHelper implements DefinitionHelper { - const DEFINITION_CLASS = ObjectDefinition::class; + private const DEFINITION_CLASS = ObjectDefinition::class; - /** - * @var string|null - */ - private $className; + private ?string $className; - /** - * @var bool|null - */ - private $lazy; + private ?bool $lazy = null; /** * Array of constructor parameters. - * @var array */ - protected $constructor = []; + protected array $constructor = []; /** * Array of properties and their value. - * @var array */ - private $properties = []; + private array $properties = []; /** * Array of methods and their parameters. - * @var array */ - protected $methods = []; + protected array $methods = []; /** * Helper for defining an object. @@ -53,7 +44,7 @@ class CreateDefinitionHelper implements DefinitionHelper * @param string|null $className Class name of the object. * If null, the name of the entry (in the container) will be used as class name. */ - public function __construct(string $className = null) + public function __construct(?string $className = null) { $this->className = $className; } @@ -65,7 +56,7 @@ public function __construct(string $className = null) * * @return $this */ - public function lazy() + public function lazy() : self { $this->lazy = true; @@ -82,7 +73,7 @@ public function lazy() * * @return $this */ - public function constructor(...$parameters) + public function constructor(...$parameters) : self { $this->constructor = $parameters; @@ -97,7 +88,7 @@ public function constructor(...$parameters) * * @return $this */ - public function property(string $property, $value) + public function property(string $property, $value) : self { $this->properties[$property] = $value; @@ -118,7 +109,7 @@ public function property(string $property, $value) * * @return $this */ - public function method(string $method, ...$parameters) + public function method(string $method, ...$parameters) : self { if (! isset($this->methods[$method])) { $this->methods[$method] = []; @@ -129,10 +120,7 @@ public function method(string $method, ...$parameters) return $this; } - /** - * @return ObjectDefinition - */ - public function getDefinition(string $entryName) : Definition + public function getDefinition(string $entryName) : ObjectDefinition { $class = $this::DEFINITION_CLASS; /** @var ObjectDefinition $definition */ diff --git a/src/Definition/Helper/FactoryDefinitionHelper.php b/src/Definition/Helper/FactoryDefinitionHelper.php index 0a223197c..09774db9d 100644 --- a/src/Definition/Helper/FactoryDefinitionHelper.php +++ b/src/Definition/Helper/FactoryDefinitionHelper.php @@ -20,15 +20,9 @@ class FactoryDefinitionHelper implements DefinitionHelper */ private $factory; - /** - * @var bool - */ - private $decorate; + private bool $decorate; - /** - * @var array - */ - private $parameters = []; + private array $parameters = []; /** * @param callable $factory @@ -40,11 +34,7 @@ public function __construct($factory, bool $decorate = false) $this->decorate = $decorate; } - /** - * @param string $entryName Container entry name - * @return FactoryDefinition - */ - public function getDefinition(string $entryName) : Definition + public function getDefinition(string $entryName) : FactoryDefinition { if ($this->decorate) { return new DecoratorDefinition($entryName, $this->factory, $this->parameters); @@ -66,7 +56,7 @@ public function getDefinition(string $entryName) : Definition * * @return $this */ - public function parameter(string $parameter, $value) + public function parameter(string $parameter, $value) : self { $this->parameters[$parameter] = $value; diff --git a/src/Definition/InstanceDefinition.php b/src/Definition/InstanceDefinition.php index 4c281c6ed..b5ea573df 100644 --- a/src/Definition/InstanceDefinition.php +++ b/src/Definition/InstanceDefinition.php @@ -14,20 +14,12 @@ class InstanceDefinition implements Definition { /** * Instance on which to inject dependencies. - * - * @var object */ - private $instance; + private object $instance; - /** - * @var ObjectDefinition - */ - private $objectDefinition; + private ObjectDefinition $objectDefinition; - /** - * @param object $instance - */ - public function __construct($instance, ObjectDefinition $objectDefinition) + public function __construct(object $instance, ObjectDefinition $objectDefinition) { $this->instance = $instance; $this->objectDefinition = $objectDefinition; @@ -39,15 +31,12 @@ public function getName() : string return ''; } - public function setName(string $name) + public function setName(string $name) : void { // Name are superfluous for instance definitions } - /** - * @return object - */ - public function getInstance() + public function getInstance() : object { return $this->instance; } @@ -57,7 +46,7 @@ public function getObjectDefinition() : ObjectDefinition return $this->objectDefinition; } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { $this->objectDefinition->replaceNestedDefinitions($replacer); } diff --git a/src/Definition/ObjectDefinition.php b/src/Definition/ObjectDefinition.php index 8d8d5b668..c116b8247 100644 --- a/src/Definition/ObjectDefinition.php +++ b/src/Definition/ObjectDefinition.php @@ -19,52 +19,35 @@ class ObjectDefinition implements Definition { /** * Entry name (most of the time, same as $classname). - * @var string */ - private $name; + private string $name; /** * Class name (if null, then the class name is $name). - * @var string|null */ - protected $className; + protected ?string $className = null; - /** - * Constructor parameter injection. - * @var MethodInjection|null - */ - protected $constructorInjection; + protected ?MethodInjection $constructorInjection = null; - /** - * Property injections. - * @var PropertyInjection[] - */ - protected $propertyInjections = []; + protected array $propertyInjections = []; /** * Method calls. * @var MethodInjection[][] */ - protected $methodInjections = []; + protected array $methodInjections = []; - /** - * @var bool|null - */ - protected $lazy; + protected ?bool $lazy = null; /** * Store if the class exists. Storing it (in cache) avoids recomputing this. - * - * @var bool */ - private $classExists; + private bool $classExists; /** * Store if the class is instantiable. Storing it (in cache) avoids recomputing this. - * - * @var bool */ - private $isInstantiable; + private bool $isInstantiable; /** * @param string $name Entry name @@ -80,7 +63,7 @@ public function getName() : string return $this->name; } - public function setName(string $name) + public function setName(string $name) : void { $this->name = $name; } @@ -101,20 +84,17 @@ public function getClassName() : string return $this->name; } - /** - * @return MethodInjection|null - */ - public function getConstructorInjection() + public function getConstructorInjection() : ?MethodInjection { return $this->constructorInjection; } - public function setConstructorInjection(MethodInjection $constructorInjection) + public function setConstructorInjection(MethodInjection $constructorInjection) : void { $this->constructorInjection = $constructorInjection; } - public function completeConstructorInjection(MethodInjection $injection) + public function completeConstructorInjection(MethodInjection $injection) : void { if ($this->constructorInjection !== null) { // Merge @@ -133,7 +113,7 @@ public function getPropertyInjections() : array return $this->propertyInjections; } - public function addPropertyInjection(PropertyInjection $propertyInjection) + public function addPropertyInjection(PropertyInjection $propertyInjection) : void { $className = $propertyInjection->getClassName(); if ($className) { @@ -161,7 +141,7 @@ public function getMethodInjections() : array return $injections; } - public function addMethodInjection(MethodInjection $methodInjection) + public function addMethodInjection(MethodInjection $methodInjection) : void { $method = $methodInjection->getMethodName(); if (! isset($this->methodInjections[$method])) { @@ -170,7 +150,7 @@ public function addMethodInjection(MethodInjection $methodInjection) $this->methodInjections[$method][] = $methodInjection; } - public function completeFirstMethodInjection(MethodInjection $injection) + public function completeFirstMethodInjection(MethodInjection $injection) : void { $method = $injection->getMethodName(); @@ -183,7 +163,7 @@ public function completeFirstMethodInjection(MethodInjection $injection) } } - public function setLazy(bool $lazy = null) + public function setLazy(bool $lazy = null) : void { $this->lazy = $lazy; } @@ -207,7 +187,7 @@ public function isInstantiable() : bool return $this->isInstantiable; } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { array_walk($this->propertyInjections, function (PropertyInjection $propertyInjection) use ($replacer) { $propertyInjection->replaceNestedDefinition($replacer); @@ -248,7 +228,7 @@ public function __toString() return (new ObjectDefinitionDumper)->dump($this); } - private function updateCache() + private function updateCache() : void { $className = $this->getClassName(); diff --git a/src/Definition/ObjectDefinition/MethodInjection.php b/src/Definition/ObjectDefinition/MethodInjection.php index 5fb67ce0a..d88b1c1a2 100644 --- a/src/Definition/ObjectDefinition/MethodInjection.php +++ b/src/Definition/ObjectDefinition/MethodInjection.php @@ -13,15 +13,12 @@ */ class MethodInjection implements Definition { - /** - * @var string - */ - private $methodName; + private string $methodName; /** * @var mixed[] */ - private $parameters = []; + private array $parameters; public function __construct(string $methodName, array $parameters = []) { @@ -66,12 +63,12 @@ public function getName() : string return ''; } - public function setName(string $name) + public function setName(string $name) : void { // The name does not matter for method injections } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { $this->parameters = array_map($replacer, $this->parameters); } diff --git a/src/Definition/ObjectDefinition/PropertyInjection.php b/src/Definition/ObjectDefinition/PropertyInjection.php index 307ba643d..85ebb9882 100644 --- a/src/Definition/ObjectDefinition/PropertyInjection.php +++ b/src/Definition/ObjectDefinition/PropertyInjection.php @@ -11,11 +11,7 @@ */ class PropertyInjection { - /** - * Property name. - * @var string - */ - private $propertyName; + private string $propertyName; /** * Value that should be injected in the property. @@ -27,9 +23,8 @@ class PropertyInjection * Use for injecting in properties of parent classes: the class name * must be the name of the parent class because private properties * can be attached to the parent classes, not the one we are resolving. - * @var string|null */ - private $className; + private ?string $className; /** * @param string $propertyName Property name @@ -55,15 +50,12 @@ public function getValue() return $this->value; } - /** - * @return string|null - */ - public function getClassName() + public function getClassName() : ?string { return $this->className; } - public function replaceNestedDefinition(callable $replacer) + public function replaceNestedDefinition(callable $replacer) : void { $this->value = $replacer($this->value); } diff --git a/src/Definition/Reference.php b/src/Definition/Reference.php index 5b4597a82..fe54ed69d 100644 --- a/src/Definition/Reference.php +++ b/src/Definition/Reference.php @@ -15,15 +15,13 @@ class Reference implements Definition, SelfResolvingDefinition { /** * Entry name. - * @var string */ - private $name = ''; + private string $name = ''; /** * Name of the target entry. - * @var string */ - private $targetEntryName; + private string $targetEntryName; /** * @param string $targetEntryName Name of the target entry @@ -38,7 +36,7 @@ public function getName() : string return $this->name; } - public function setName(string $name) + public function setName(string $name) : void { $this->name = $name; } @@ -58,7 +56,7 @@ public function isResolvable(ContainerInterface $container) : bool return $container->has($this->getTargetEntryName()); } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { // no nested definitions } diff --git a/src/Definition/Resolver/ArrayResolver.php b/src/Definition/Resolver/ArrayResolver.php index 72d5ed4c0..20446474a 100644 --- a/src/Definition/Resolver/ArrayResolver.php +++ b/src/Definition/Resolver/ArrayResolver.php @@ -17,10 +17,7 @@ */ class ArrayResolver implements DefinitionResolver { - /** - * @var DefinitionResolver - */ - private $definitionResolver; + private DefinitionResolver $definitionResolver; /** * @param DefinitionResolver $definitionResolver Used to resolve nested definitions. diff --git a/src/Definition/Resolver/DecoratorResolver.php b/src/Definition/Resolver/DecoratorResolver.php index 03585eae5..8e54ce6f2 100644 --- a/src/Definition/Resolver/DecoratorResolver.php +++ b/src/Definition/Resolver/DecoratorResolver.php @@ -17,15 +17,9 @@ */ class DecoratorResolver implements DefinitionResolver { - /** - * @var ContainerInterface - */ - private $container; + private ContainerInterface $container; - /** - * @var DefinitionResolver - */ - private $definitionResolver; + private DefinitionResolver $definitionResolver; /** * The resolver needs a container. This container will be passed to the factory as a parameter diff --git a/src/Definition/Resolver/EnvironmentVariableResolver.php b/src/Definition/Resolver/EnvironmentVariableResolver.php index 4ba0b3e53..26ba4737f 100644 --- a/src/Definition/Resolver/EnvironmentVariableResolver.php +++ b/src/Definition/Resolver/EnvironmentVariableResolver.php @@ -15,10 +15,7 @@ */ class EnvironmentVariableResolver implements DefinitionResolver { - /** - * @var DefinitionResolver - */ - private $definitionResolver; + private DefinitionResolver $definitionResolver; /** * @var callable diff --git a/src/Definition/Resolver/FactoryResolver.php b/src/Definition/Resolver/FactoryResolver.php index c36a1aa7b..8bd87692f 100644 --- a/src/Definition/Resolver/FactoryResolver.php +++ b/src/Definition/Resolver/FactoryResolver.php @@ -25,20 +25,11 @@ */ class FactoryResolver implements DefinitionResolver { - /** - * @var ContainerInterface - */ - private $container; + private ContainerInterface $container; - /** - * @var Invoker|null - */ - private $invoker; + private ?Invoker $invoker = null; - /** - * @var DefinitionResolver - */ - private $resolver; + private DefinitionResolver $resolver; /** * The resolver needs a container. This container will be passed to the factory as a parameter diff --git a/src/Definition/Resolver/InstanceInjector.php b/src/Definition/Resolver/InstanceInjector.php index 60ea24a3a..212b75978 100644 --- a/src/Definition/Resolver/InstanceInjector.php +++ b/src/Definition/Resolver/InstanceInjector.php @@ -22,7 +22,7 @@ class InstanceInjector extends ObjectCreator * * @param InstanceDefinition $definition */ - public function resolve(Definition $definition, array $parameters = []) + public function resolve(Definition $definition, array $parameters = []) : ?object { try { $this->injectMethodsAndProperties($definition->getInstance(), $definition->getObjectDefinition()); diff --git a/src/Definition/Resolver/ObjectCreator.php b/src/Definition/Resolver/ObjectCreator.php index 97b9defd3..38e205dac 100644 --- a/src/Definition/Resolver/ObjectCreator.php +++ b/src/Definition/Resolver/ObjectCreator.php @@ -24,20 +24,11 @@ */ class ObjectCreator implements DefinitionResolver { - /** - * @var ProxyFactory - */ - private $proxyFactory; + private ProxyFactory $proxyFactory; - /** - * @var ParameterResolver - */ - private $parameterResolver; + private ParameterResolver $parameterResolver; - /** - * @var DefinitionResolver - */ - private $definitionResolver; + private DefinitionResolver $definitionResolver; /** * @param DefinitionResolver $definitionResolver Used to resolve nested definitions. @@ -58,10 +49,8 @@ public function __construct( * This will create a new instance of the class using the injections points defined. * * @param ObjectDefinition $definition - * - * @return object|null */ - public function resolve(Definition $definition, array $parameters = []) + public function resolve(Definition $definition, array $parameters = []) : ?object { // Lazy? if ($definition->isLazy()) { @@ -87,7 +76,6 @@ public function isResolvable(Definition $definition, array $parameters = []) : b */ private function createProxy(ObjectDefinition $definition, array $parameters) : LazyLoadingInterface { - /** @noinspection PhpUnusedParameterInspection */ $proxy = $this->proxyFactory->createProxy( $definition->getClassName(), function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($definition, $parameters) { @@ -103,13 +91,12 @@ function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($defi /** * Creates an instance of the class and injects dependencies.. * - * @param array $parameters Optional parameters to use to create the instance. + * @param array $parameters Optional parameters to use to create the instance. * - * @throws InvalidDefinition * @throws DependencyException - * @return object + * @throws InvalidDefinition */ - private function createInstance(ObjectDefinition $definition, array $parameters) + private function createInstance(ObjectDefinition $definition, array $parameters) : object { // Check that the class is instantiable if (! $definition->isInstantiable()) { @@ -159,7 +146,7 @@ private function createInstance(ObjectDefinition $definition, array $parameters) return $object; } - protected function injectMethodsAndProperties($object, ObjectDefinition $objectDefinition) + protected function injectMethodsAndProperties($object, ObjectDefinition $objectDefinition) : void { // Property injections foreach ($objectDefinition->getPropertyInjections() as $propertyInjection) { @@ -184,7 +171,7 @@ protected function injectMethodsAndProperties($object, ObjectDefinition $objectD * @throws DependencyException * @throws InvalidDefinition */ - private function injectProperty($object, PropertyInjection $propertyInjection) + private function injectProperty($object, PropertyInjection $propertyInjection) : void { $propertyName = $propertyInjection->getPropertyName(); @@ -208,7 +195,7 @@ private function injectProperty($object, PropertyInjection $propertyInjection) self::setPrivatePropertyValue($propertyInjection->getClassName(), $object, $propertyName, $value); } - public static function setPrivatePropertyValue(string $className = null, $object, string $propertyName, $propertyValue) + public static function setPrivatePropertyValue(string $className = null, $object, string $propertyName, $propertyValue) : void { $className = $className ?: get_class($object); diff --git a/src/Definition/Resolver/ParameterResolver.php b/src/Definition/Resolver/ParameterResolver.php index c9a4640eb..b786b9cf1 100644 --- a/src/Definition/Resolver/ParameterResolver.php +++ b/src/Definition/Resolver/ParameterResolver.php @@ -18,10 +18,7 @@ */ class ParameterResolver { - /** - * @var DefinitionResolver - */ - private $definitionResolver; + private DefinitionResolver $definitionResolver; /** * @param DefinitionResolver $definitionResolver Will be used to resolve nested definitions. diff --git a/src/Definition/Resolver/ResolverDispatcher.php b/src/Definition/Resolver/ResolverDispatcher.php index 7c0edcc58..67f20f832 100644 --- a/src/Definition/Resolver/ResolverDispatcher.php +++ b/src/Definition/Resolver/ResolverDispatcher.php @@ -26,22 +26,16 @@ */ class ResolverDispatcher implements DefinitionResolver { - /** - * @var ContainerInterface - */ - private $container; + private ContainerInterface $container; - /** - * @var ProxyFactory - */ - private $proxyFactory; - - private $arrayResolver; - private $factoryResolver; - private $decoratorResolver; - private $objectResolver; - private $instanceResolver; - private $envVariableResolver; + private ProxyFactory $proxyFactory; + + private ?ArrayResolver $arrayResolver = null; + private ?FactoryResolver $factoryResolver = null; + private ?DecoratorResolver $decoratorResolver = null; + private ?ObjectCreator $objectResolver = null; + private ?InstanceInjector $instanceResolver = null; + private ?EnvironmentVariableResolver $envVariableResolver = null; public function __construct(ContainerInterface $container, ProxyFactory $proxyFactory) { diff --git a/src/Definition/StringDefinition.php b/src/Definition/StringDefinition.php index 52207e76e..e901338ab 100644 --- a/src/Definition/StringDefinition.php +++ b/src/Definition/StringDefinition.php @@ -18,14 +18,10 @@ class StringDefinition implements Definition, SelfResolvingDefinition { /** * Entry name. - * @var string */ - private $name = ''; + private string $name = ''; - /** - * @var string - */ - private $expression; + private string $expression; public function __construct(string $expression) { @@ -37,7 +33,7 @@ public function getName() : string return $this->name; } - public function setName(string $name) + public function setName(string $name) : void { $this->name = $name; } @@ -57,7 +53,7 @@ public function isResolvable(ContainerInterface $container) : bool return true; } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { // no nested definitions } diff --git a/src/Definition/ValueDefinition.php b/src/Definition/ValueDefinition.php index d64758291..560ece7c6 100644 --- a/src/Definition/ValueDefinition.php +++ b/src/Definition/ValueDefinition.php @@ -15,9 +15,8 @@ class ValueDefinition implements Definition, SelfResolvingDefinition { /** * Entry name. - * @var string */ - private $name = ''; + private string $name = ''; /** * @var mixed @@ -37,7 +36,7 @@ public function getName() : string return $this->name; } - public function setName(string $name) + public function setName(string $name) : void { $this->name = $name; } @@ -60,7 +59,7 @@ public function isResolvable(ContainerInterface $container) : bool return true; } - public function replaceNestedDefinitions(callable $replacer) + public function replaceNestedDefinitions(callable $replacer) : void { // no nested definitions } diff --git a/src/FactoryInterface.php b/src/FactoryInterface.php index 59b410ff2..322344ebb 100644 --- a/src/FactoryInterface.php +++ b/src/FactoryInterface.php @@ -27,5 +27,5 @@ interface FactoryInterface * @throws NotFoundException No entry or class found for the given name. * @return mixed */ - public function make($name, array $parameters = []); + public function make(string $name, array $parameters = []); } diff --git a/src/Invoker/DefinitionParameterResolver.php b/src/Invoker/DefinitionParameterResolver.php index b17ebd9fd..cb1582943 100644 --- a/src/Invoker/DefinitionParameterResolver.php +++ b/src/Invoker/DefinitionParameterResolver.php @@ -18,10 +18,7 @@ */ class DefinitionParameterResolver implements ParameterResolver { - /** - * @var DefinitionResolver - */ - private $definitionResolver; + private DefinitionResolver $definitionResolver; public function __construct(DefinitionResolver $definitionResolver) { diff --git a/src/Invoker/FactoryParameterResolver.php b/src/Invoker/FactoryParameterResolver.php index ee87e28df..2cb6cc089 100644 --- a/src/Invoker/FactoryParameterResolver.php +++ b/src/Invoker/FactoryParameterResolver.php @@ -20,10 +20,7 @@ */ class FactoryParameterResolver implements ParameterResolver { - /** - * @var ContainerInterface - */ - private $container; + private ContainerInterface $container; public function __construct(ContainerInterface $container) { diff --git a/src/Proxy/ProxyFactory.php b/src/Proxy/ProxyFactory.php index 39b8e2aac..542ae804f 100644 --- a/src/Proxy/ProxyFactory.php +++ b/src/Proxy/ProxyFactory.php @@ -25,20 +25,15 @@ class ProxyFactory { /** * If true, write the proxies to disk to improve performances. - * @var bool */ - private $writeProxiesToFile; + private bool $writeProxiesToFile; /** * Directory where to write the proxies (if $writeProxiesToFile is enabled). - * @var string|null */ - private $proxyDirectory; + private ?string $proxyDirectory; - /** - * @var LazyLoadingValueHolderFactory|null - */ - private $proxyManager; + private ?LazyLoadingValueHolderFactory $proxyManager = null; public function __construct(bool $writeProxiesToFile = false, string $proxyDirectory = null) { @@ -65,7 +60,7 @@ public function createProxy(string $className, \Closure $initializer) : LazyLoad * * @param string $className name of the class to be proxied */ - public function generateProxyClass(string $className) + public function generateProxyClass(string $className) : void { // If proxy classes a written to file then we pre-generate the class // If they are not written to file then there is no point to do this @@ -75,7 +70,7 @@ public function generateProxyClass(string $className) } } - private function createProxyManager() + private function createProxyManager() : void { if ($this->proxyManager !== null) { return; diff --git a/src/functions.php b/src/functions.php index 0504edb58..f53651f69 100644 --- a/src/functions.php +++ b/src/functions.php @@ -32,7 +32,7 @@ function value($value) : ValueDefinition * @param string|null $className Class name of the object. * If null, the name of the entry (in the container) will be used as class name. */ - function create(string $className = null) : CreateDefinitionHelper + function create(?string $className = null) : CreateDefinitionHelper { return new CreateDefinitionHelper($className); } @@ -45,7 +45,7 @@ function create(string $className = null) : CreateDefinitionHelper * @param string|null $className Class name of the object. * If null, the name of the entry (in the container) will be used as class name. */ - function autowire(string $className = null) : AutowireDefinitionHelper + function autowire(?string $className = null) : AutowireDefinitionHelper { return new AutowireDefinitionHelper($className); } diff --git a/tests/IntegrationTest/ContainerInjectOnTest.php b/tests/IntegrationTest/ContainerInjectOnTest.php index 38913429e..e2500fa1f 100644 --- a/tests/IntegrationTest/ContainerInjectOnTest.php +++ b/tests/IntegrationTest/ContainerInjectOnTest.php @@ -30,14 +30,6 @@ public function test_returns_the_same_object(ContainerBuilder $builder) self::assertSame($instance, $builder->build()->injectOn($instance)); } - /** - * @dataProvider provideContainer - */ - public function test_inject_on_null_returns_null(ContainerBuilder $builder) - { - self::assertNull($builder->build()->injectOn(null)); - } - /** * @dataProvider provideContainer */ diff --git a/tests/IntegrationTest/ContainerMakeTest.php b/tests/IntegrationTest/ContainerMakeTest.php index 5985597ce..a8828a3ab 100644 --- a/tests/IntegrationTest/ContainerMakeTest.php +++ b/tests/IntegrationTest/ContainerMakeTest.php @@ -90,16 +90,6 @@ public function testCircularDependencyExceptionWithAlias(ContainerBuilder $build $container->make('foo'); } - /** - * @dataProvider provideContainer - */ - public function testNonStringParameter(ContainerBuilder $builder) - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('The name parameter must be of type string'); - $builder->build()->make(new stdClass); - } - /** * Tests a dependency can be made when a dependency is passed by reference. * @dataProvider provideContainer From 3d9ac0c69014acc66d4bfac89d29994d83e75cf2 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 1 Aug 2020 23:17:44 +0200 Subject: [PATCH 05/45] Fix coding style --- src/CompiledContainer.php | 4 ++-- src/Container.php | 4 ++-- src/ContainerBuilder.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CompiledContainer.php b/src/CompiledContainer.php index b80ec226a..30f1ce81c 100644 --- a/src/CompiledContainer.php +++ b/src/CompiledContainer.php @@ -64,7 +64,7 @@ public function get($name) /** * {@inheritdoc} */ - public function has($name): bool + public function has($name) : bool { if (! is_string($name)) { throw new \InvalidArgumentException(sprintf( @@ -81,7 +81,7 @@ public function has($name): bool return parent::has($name); } - protected function setDefinition(string $name, Definition $definition): void + protected function setDefinition(string $name, Definition $definition) : void { // It needs to be forbidden because that would mean get() must go through the definitions // every time, which kinds of defeats the performance gains of the compiled container diff --git a/src/Container.php b/src/Container.php index 7f8f0aba2..c385c28e1 100644 --- a/src/Container.php +++ b/src/Container.php @@ -183,7 +183,7 @@ public function make(string $name, array $parameters = []) * * @throws InvalidArgumentException The name parameter must be of type string. */ - public function has($name): bool + public function has($name) : bool { if (! is_string($name)) { throw new InvalidArgumentException(sprintf( @@ -212,7 +212,7 @@ public function has($name): bool * @throws DependencyException Error while injecting dependencies * @return object $instance Returns the same instance */ - public function injectOn(object $instance): object + public function injectOn(object $instance) : object { $className = get_class($instance); diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index 56d34dcf0..7b014e4c7 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -337,7 +337,7 @@ public function isCompilationEnabled() : bool return (bool) $this->compileToDirectory; } - private function ensureNotLocked(): void + private function ensureNotLocked() : void { if ($this->locked) { throw new \LogicException('The ContainerBuilder cannot be modified after the container has been built'); From 4cdea6cb352afac202bcb6863d520c4f942ab74c Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 1 Aug 2020 23:18:06 +0200 Subject: [PATCH 06/45] Remove useless config files --- .coveralls.yml | 2 -- .styleci.yml | 17 ----------------- 2 files changed, 19 deletions(-) delete mode 100644 .coveralls.yml delete mode 100644 .styleci.yml diff --git a/.coveralls.yml b/.coveralls.yml deleted file mode 100644 index bc71b62f8..000000000 --- a/.coveralls.yml +++ /dev/null @@ -1,2 +0,0 @@ -coverage_clover: clover.xml -json_path: coveralls-upload.json diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index df0611659..000000000 --- a/.styleci.yml +++ /dev/null @@ -1,17 +0,0 @@ -preset: recommended - -enabled: - - phpdoc_no_empty_return - - concat_with_spaces - - declare_strict_types - -disabled: - - phpdoc_to_comment - - unary_operators_spaces - - concat_without_spaces - - empty_return - - new_with_braces - - phpdoc_align - - phpdoc_separation - - align_double_arrow - - no_unreachable_default_argument_value From a74041b9465197184b0c0cd45c2a2353b2632136 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 1 Aug 2020 23:24:22 +0200 Subject: [PATCH 07/45] Update dependency versions to fix tests --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 134ac2a70..8fd5b7c0d 100644 --- a/composer.json +++ b/composer.json @@ -33,8 +33,8 @@ "require-dev": { "phpunit/phpunit": "^9.3-dev", "mnapoli/phpunit-easymock": "^1.3", - "doctrine/annotations": "~1.2", - "ocramius/proxy-manager": "~2.0.2", + "doctrine/annotations": "^1.7", + "ocramius/proxy-manager": "^2.3", "friendsofphp/php-cs-fixer": "^2.4", "phpstan/phpstan": "^0.12" }, @@ -42,8 +42,8 @@ "psr/container-implementation": "^1.0" }, "suggest": { - "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", - "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" + "doctrine/annotations": "Install it if you want to use annotations (version ^1.7)", + "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ^2.3)" }, "minimum-stability": "dev", "prefer-stable": true From 35854423241d8a2d71376aa2d4742c607108b158 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sun, 2 Aug 2020 09:54:11 +0200 Subject: [PATCH 08/45] Improve support for PHP 8 --- tests/IntegrationTest/Definitions/AutowireDefinitionTest.php | 1 + tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php index 99e817a5e..3c47db63e 100644 --- a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php @@ -317,6 +317,7 @@ public function test_autowire_lazy_object(ContainerBuilder $builder) /** * @dataProvider provideContainer + * @requires PHP < 8 */ public function test_optional_parameter_followed_by_required_parameters(ContainerBuilder $builder) { diff --git a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php index b10b40d6c..ab73e8e35 100644 --- a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php +++ b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php @@ -167,6 +167,7 @@ public function test_factory_not_callable(ContainerBuilder $builder) /** * @dataProvider provideContainer + * @requires PHP < 8 */ public function test_internal_class_default_parameter_value(ContainerBuilder $builder) { From 15ef9d571fce486f8b3f69f34db3976b04bb4d27 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Mon, 28 Sep 2020 14:22:01 +0200 Subject: [PATCH 09/45] Inject via PHP 8 attributes --- couscous.yml | 3 + doc/annotations.md | 4 + doc/attributes.md | 127 ++++++++ doc/best-practices.md | 12 +- src/Attribute/Inject.php | 76 +++++ src/Attribute/Injectable.php | 38 +++ src/ContainerBuilder.php | 24 +- .../Helper/CreateDefinitionHelper.php | 1 - src/Definition/Resolver/ObjectCreator.php | 1 + .../Source/AttributeBasedAutowiring.php | 272 ++++++++++++++++++ tests/IntegrationTest/Attributes/A.php | 9 + .../Attributes/AttributesTest.php | 108 +++++++ tests/IntegrationTest/Attributes/B.php | 29 ++ tests/IntegrationTest/Attributes/C.php | 9 + tests/IntegrationTest/Attributes/Child.php | 18 ++ tests/IntegrationTest/Attributes/D.php | 9 + .../Attributes/NamedInjection.php | 16 ++ .../Definitions/AttributeTest.php | 179 ++++++++++++ .../Attributes/Fixtures/Dependency.php | 9 + .../Attributes/Fixtures/InjectFixture.php | 42 +++ .../Attributes/Fixtures/Injectable1.php | 10 + .../Attributes/Fixtures/Injectable2.php | 10 + tests/UnitTest/Attributes/InjectTest.php | 103 +++++++ tests/UnitTest/Attributes/InjectableTest.php | 54 ++++ 24 files changed, 1155 insertions(+), 8 deletions(-) create mode 100644 doc/attributes.md create mode 100644 src/Attribute/Inject.php create mode 100644 src/Attribute/Injectable.php create mode 100644 src/Definition/Source/AttributeBasedAutowiring.php create mode 100644 tests/IntegrationTest/Attributes/A.php create mode 100644 tests/IntegrationTest/Attributes/AttributesTest.php create mode 100644 tests/IntegrationTest/Attributes/B.php create mode 100644 tests/IntegrationTest/Attributes/C.php create mode 100644 tests/IntegrationTest/Attributes/Child.php create mode 100644 tests/IntegrationTest/Attributes/D.php create mode 100644 tests/IntegrationTest/Attributes/NamedInjection.php create mode 100644 tests/IntegrationTest/Definitions/AttributeTest.php create mode 100644 tests/UnitTest/Attributes/Fixtures/Dependency.php create mode 100644 tests/UnitTest/Attributes/Fixtures/InjectFixture.php create mode 100644 tests/UnitTest/Attributes/Fixtures/Injectable1.php create mode 100644 tests/UnitTest/Attributes/Fixtures/Injectable2.php create mode 100644 tests/UnitTest/Attributes/InjectTest.php create mode 100644 tests/UnitTest/Attributes/InjectableTest.php diff --git a/couscous.yml b/couscous.yml index 1ccecaa20..6b4a29941 100644 --- a/couscous.yml +++ b/couscous.yml @@ -46,6 +46,9 @@ menu: php-definitions: text: PHP definitions url: doc/php-definitions.html + attributes: + text: PHP 8 attributes + url: doc/attributes.html annotations: text: Annotations url: doc/annotations.html diff --git a/doc/annotations.md b/doc/annotations.md index 0d545c5e6..daa88824d 100644 --- a/doc/annotations.md +++ b/doc/annotations.md @@ -5,6 +5,10 @@ current_menu: annotations # Annotations +**Since PHP 8, annotations are deprecated in favor of [PHP attributes](attributes.md).** + +--- + On top of [autowiring](autowiring.md) and [PHP configuration files](php-definitions.md), you can define injections using annotations. Using annotations do not affect performances when [compiling the container](performances.md). diff --git a/doc/attributes.md b/doc/attributes.md new file mode 100644 index 000000000..8a8bbcf59 --- /dev/null +++ b/doc/attributes.md @@ -0,0 +1,127 @@ +--- +layout: documentation +current_menu: attributes +--- + +# Attributes + +On top of [autowiring](autowiring.md) and [PHP configuration files](php-definitions.md), you can define injections using PHP 8 attributes. + +Using attributes do not affect performances when [compiling the container](performances.md). For a non-compiled container, the PHP reflection is used but the overhead is minimal. + +## Setup + +Enable attributes [via the `ContainerBuilder`](container-configuration.md): + +```php +$containerBuilder->useAttributes(true); +``` + +## Inject + +`#[Inject]` lets you define where PHP-DI should inject something, and optionally what it should inject. + +It can be used on: + +- the constructor (constructor injection) +- methods (setter/method injection) +- properties (property injection) + +*Note: property injections occur after the constructor is executed, so any injectable property will be null inside `__construct`.* + +**Note: `#[Inject]` ignores types declared in phpdoc. Only types specified in PHP code are considered.** + +Here is an example of all possible uses of the `#[Inject]` attribute: + +```php +use DI\Attribute\Inject; + +class Example +{ + /** + * Attribute combined with a type on the property: + */ + #[Inject] + private Foo $property1; + + /** + * Explicit definition of the entry to inject: + */ + #[Inject('db.host')] + private $property2; + + /** + * Alternative to the above: + */ + #[Inject(name: 'db.host')] + private $property3; + + /** + * Attribute specifying exactly what to inject on the constructor: + */ + #[Inject(['db.host', 'db.name'])] + public function __construct($param1, $param2) + { + } + + /** + * Attribute combined with PHP types: + */ + #[Inject] + public function method1(Foo $param) + { + } + + /** + * Explicit definition of the entries to inject: + */ + #[Inject(['db.host', 'db.name'])] + public function method2($param1, $param2) + { + } + + /** + * Explicit definition of parameters by their name + * (types are used for the other parameters): + */ + #[Inject(['param2' => 'db.host'])] + public function method3(Foo $param1, $param2) + { + } +} +``` + +*Note: remember to import the attribute class via `use DI\Attribute\Inject;`.* + +### Troubleshooting attributes + +- remember to import the attribute class via `use DI\Attribute\Inject;` +- `#[Inject]` is not meant to be used on the method to call with [`Container::call()`](container.md#call) (it will be ignored) +- `#[Inject]` ignores types declared in phpdoc. Only types specified in PHP code are considered. + +Note that `#[Inject]` is implicit on all constructors (because constructors must be called to create an object). + +## Injectable + +The `#[Injectable]` attribute lets you set options on injectable classes: + +```php +use DI\Attribute\Injectable; + +#[Injectable(lazy: true)] +class Example +{ +} +``` + +**The `#[Injectable]` attribute is optional: by default, all classes are injectable.** + +## Limitations + +There are things that can't be defined with attributes: + +- values (instead of classes) +- mapping interfaces to implementations +- defining entries with an anonymous function + +For that, you can combine attributes with [definitions in PHP](php-definitions.md). diff --git a/doc/best-practices.md b/doc/best-practices.md index c59cd7381..26c7abf3b 100644 --- a/doc/best-practices.md +++ b/doc/best-practices.md @@ -46,11 +46,11 @@ This is the solution we recommend. Example: ```php + + class UserController { - /** - * @Inject - */ + #[Inject] private FormFactoryInterface $formFactory; public function createForm($type, $data, $options) @@ -67,7 +67,7 @@ Property injection is generally frowned upon, and for good reasons: - injecting in a private property breaks encapsulation - it is not an explicit dependency: there is no contract saying your class need the property to be set to work -- if you use PHP-DI's annotations to mark the dependency to be injected, your class is dependent on the container (see the 2nd rule above) +- if you use PHP-DI's attributes to mark the dependency to be injected, your class is dependent on the container (see the 2nd rule above) BUT @@ -82,13 +82,13 @@ So: (because most dependencies like Request, Response, templating system, etc. will have changed) This solution offers many benefits for no major drawback, so -**we recommend using annotations in controllers**. +**we recommend using attributes in controllers**. ## Writing services Given a service is intended to be reused, tested and independent of your framework, **we do not recommend -using annotations for injecting dependencies**. +using attributes for injecting dependencies**. Instead, we recommend using **constructor injection and autowiring**: diff --git a/src/Attribute/Inject.php b/src/Attribute/Inject.php new file mode 100644 index 000000000..5a6de250d --- /dev/null +++ b/src/Attribute/Inject.php @@ -0,0 +1,76 @@ + + */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)] +final class Inject +{ + /** + * Entry name. + */ + private ?string $name = null; + + /** + * Parameters, indexed by the parameter number (index) or name. + * + * Used if the annotation is set on a method + */ + private array $parameters = []; + + /** + * @param string|array|null $name + * + * @throws InvalidAnnotation + */ + public function __construct($name = null) + { + // #[Inject('foo')] or #[Inject(name: 'foo')] + if (is_string($name)) { + $this->name = $name; + } + + // #[Inject([...])] on a method + if (is_array($name)) { + foreach ($name as $key => $value) { + if (! is_string($value)) { + throw new InvalidAnnotation(sprintf( + "#[Inject(['param' => 'value'])] expects \"value\" to be a string, %s given.", + json_encode($value, JSON_THROW_ON_ERROR) + )); + } + + $this->parameters[$key] = $value; + } + } + } + + /** + * @return string|null Name of the entry to inject + */ + public function getName() : ?string + { + return $this->name; + } + + /** + * @return array Parameters, indexed by the parameter number (index) or name + */ + public function getParameters() : array + { + return $this->parameters; + } +} diff --git a/src/Attribute/Injectable.php b/src/Attribute/Injectable.php new file mode 100644 index 000000000..bc8acd12e --- /dev/null +++ b/src/Attribute/Injectable.php @@ -0,0 +1,38 @@ + + * @author Matthieu Napoli + */ +#[Attribute(Attribute::TARGET_CLASS)] +final class Injectable +{ + /** + * Should the object be lazy-loaded. + */ + private ?bool $lazy = null; + + public function __construct(array $values) + { + if (isset($values['lazy'])) { + $this->lazy = (bool) $values['lazy']; + } + } + + public function isLazy() : ?bool + { + return $this->lazy; + } +} diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index 7b014e4c7..c1b695ffc 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -6,6 +6,7 @@ use DI\Compiler\Compiler; use DI\Definition\Source\AnnotationBasedAutowiring; +use DI\Definition\Source\AttributeBasedAutowiring; use DI\Definition\Source\DefinitionArray; use DI\Definition\Source\DefinitionFile; use DI\Definition\Source\DefinitionSource; @@ -48,6 +49,8 @@ class ContainerBuilder private bool $useAnnotations = false; + private bool $useAttributes = false; + /** * If true, write the proxies to disk to improve performances. */ @@ -104,7 +107,10 @@ public function build() { $sources = array_reverse($this->definitionSources); - if ($this->useAnnotations) { + if ($this->useAttributes) { + $autowiring = new AttributeBasedAutowiring; + $sources[] = $autowiring; + } elseif ($this->useAnnotations) { $autowiring = new AnnotationBasedAutowiring; $sources[] = $autowiring; } elseif ($this->useAutowiring) { @@ -228,6 +234,22 @@ public function useAnnotations(bool $bool) : self return $this; } + /** + * Enable or disable the use of PHP 8 attributes to configure injections. + * + * Disabled by default. + * + * @return $this + */ + public function useAttributes(bool $bool) : self + { + $this->ensureNotLocked(); + + $this->useAttributes = $bool; + + return $this; + } + /** * Configure the proxy generation. * diff --git a/src/Definition/Helper/CreateDefinitionHelper.php b/src/Definition/Helper/CreateDefinitionHelper.php index bba3a34d7..90c1b439b 100644 --- a/src/Definition/Helper/CreateDefinitionHelper.php +++ b/src/Definition/Helper/CreateDefinitionHelper.php @@ -4,7 +4,6 @@ namespace DI\Definition\Helper; -use DI\Definition\Definition; use DI\Definition\Exception\InvalidDefinition; use DI\Definition\ObjectDefinition; use DI\Definition\ObjectDefinition\MethodInjection; diff --git a/src/Definition/Resolver/ObjectCreator.php b/src/Definition/Resolver/ObjectCreator.php index 38e205dac..cefa7553f 100644 --- a/src/Definition/Resolver/ObjectCreator.php +++ b/src/Definition/Resolver/ObjectCreator.php @@ -81,6 +81,7 @@ private function createProxy(ObjectDefinition $definition, array $parameters) : function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($definition, $parameters) { $wrappedObject = $this->createInstance($definition, $parameters); $initializer = null; // turning off further lazy initialization + return true; } ); diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php new file mode 100644 index 000000000..601b79291 --- /dev/null +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -0,0 +1,272 @@ + + */ +class AttributeBasedAutowiring implements DefinitionSource, Autowiring +{ + public function __construct() + { + if (\PHP_VERSION_ID < 80000) { + throw new \Exception('Using PHP 8 attributes for autowiring is only supported with PHP 8'); + } + } + + /** + * @throws InvalidAnnotation + */ + public function autowire(string $name, ObjectDefinition $definition = null) + { + $className = $definition ? $definition->getClassName() : $name; + + if (!class_exists($className) && !interface_exists($className)) { + return $definition; + } + + $definition = $definition ?: new ObjectDefinition($name); + + $class = new ReflectionClass($className); + + $this->readInjectableAttribute($class, $definition); + + // Browse the class properties looking for annotated properties + $this->readProperties($class, $definition); + + // Browse the object's methods looking for annotated methods + $this->readMethods($class, $definition); + + return $definition; + } + + /** + * {@inheritdoc} + * @throws InvalidAnnotation + * @throws InvalidArgumentException The class doesn't exist + */ + public function getDefinition(string $name) + { + return $this->autowire($name); + } + + /** + * Autowiring cannot guess all existing definitions. + */ + public function getDefinitions() : array + { + return []; + } + + /** + * Browse the class properties looking for annotated properties. + */ + private function readProperties(ReflectionClass $class, ObjectDefinition $definition) + { + foreach ($class->getProperties() as $property) { + if ($property->isStatic()) { + continue; + } + $this->readProperty($property, $definition); + } + + // Read also the *private* properties of the parent classes + /** @noinspection PhpAssignmentInConditionInspection */ + while ($class = $class->getParentClass()) { + foreach ($class->getProperties(ReflectionProperty::IS_PRIVATE) as $property) { + if ($property->isStatic()) { + continue; + } + $this->readProperty($property, $definition, $class->getName()); + } + } + } + + /** + * @throws InvalidAnnotation + */ + private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, $classname = null) : void + { + // Look for #[Inject] annotation + try { + $attribute = $property->getAttributes(Inject::class)[0] ?? null; + if (! $attribute) { + return; + } + /** @var Inject $inject */ + $inject = $attribute->newInstance(); + } catch (Throwable $e) { + throw new InvalidAnnotation(sprintf( + '#[Inject] annotation on property %s::%s is malformed. %s', + $property->getDeclaringClass()->getName(), + $property->getName(), + $e->getMessage() + ), 0, $e); + } + + // Try to #[Inject("name")] or look for the property type + $entryName = $inject->getName(); + + // Try using typed properties + $propertyType = $property->getType(); + if ($entryName === null && $propertyType instanceof ReflectionNamedType) { + if (! class_exists($propertyType->getName()) && ! interface_exists($propertyType->getName())) { + throw new InvalidAnnotation(sprintf( + '#[Inject] found on property %s::%s but unable to guess what to inject, the type of the property does not look like a valid class or interface name', + $property->getDeclaringClass()->getName(), + $property->getName() + )); + } + $entryName = $propertyType->getName(); + } + + if ($entryName === null) { + throw new InvalidAnnotation(sprintf( + '#[Inject] found on property %s::%s but unable to guess what to inject, please add a type to the property', + $property->getDeclaringClass()->getName(), + $property->getName() + )); + } + + $definition->addPropertyInjection( + new PropertyInjection($property->getName(), new Reference($entryName), $classname) + ); + } + + /** + * Browse the object's methods looking for annotated methods. + */ + private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition) + { + // This will look in all the methods, including those of the parent classes + foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + if ($method->isStatic()) { + continue; + } + + $methodInjection = $this->getMethodInjection($method); + + if (! $methodInjection) { + continue; + } + + if ($method->isConstructor()) { + $objectDefinition->completeConstructorInjection($methodInjection); + } else { + $objectDefinition->completeFirstMethodInjection($methodInjection); + } + } + } + + /** + * @throws InvalidAnnotation + */ + private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection + { + // Look for #[Inject] attribute + try { + $attribute = $method->getAttributes(Inject::class)[0] ?? null; + if (! $attribute) { + return null; + } + /** @var Inject $inject */ + $inject = $attribute->newInstance(); + } catch (Throwable $e) { + throw new InvalidAnnotation(sprintf( + '#[Inject] annotation on %s::%s() is malformed. %s', + $method->getDeclaringClass()->getName(), + $method->getName(), + $e->getMessage() + ), 0, $e); + } + + $annotationParameters = $inject->getParameters(); + + $parameters = []; + foreach ($method->getParameters() as $index => $parameter) { + $entryName = $this->getMethodParameter($index, $parameter, $annotationParameters); + + if ($entryName !== null) { + $parameters[$index] = new Reference($entryName); + } + } + + if ($method->isConstructor()) { + return MethodInjection::constructor($parameters); + } + + return new MethodInjection($method->getName(), $parameters); + } + + /** + * @return string|null Entry name or null if not found. + */ + private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters) : ?string + { + // #[Inject] has definition for this parameter (by index, or by name) + if (isset($annotationParameters[$parameterIndex])) { + return $annotationParameters[$parameterIndex]; + } + if (isset($annotationParameters[$parameter->getName()])) { + return $annotationParameters[$parameter->getName()]; + } + + // Skip optional parameters if not explicitly defined + if ($parameter->isOptional()) { + return null; + } + + // Look for the property type + $parameterType = $parameter->getType(); + if ($parameterType && !$parameterType->isBuiltin() && $parameterType instanceof ReflectionNamedType) { + return $parameterType->getName(); + } + + return null; + } + + /** + * @throws InvalidAnnotation + */ + private function readInjectableAttribute(ReflectionClass $class, ObjectDefinition $definition) : void + { + try { + $attribute = $class->getAttributes(Injectable::class)[0] ?? null; + if (! $attribute) { + return; + } + $attribute = $attribute->newInstance(); + } catch (Throwable $e) { + throw new InvalidAnnotation(sprintf( + 'Error while reading #[Injectable] on %s: %s', + $class->getName(), + $e->getMessage() + ), 0, $e); + } + + if ($attribute->isLazy() !== null) { + $definition->setLazy($attribute->isLazy()); + } + } +} diff --git a/tests/IntegrationTest/Attributes/A.php b/tests/IntegrationTest/Attributes/A.php new file mode 100644 index 000000000..1b5030a08 --- /dev/null +++ b/tests/IntegrationTest/Attributes/A.php @@ -0,0 +1,9 @@ += 8 + */ +class AttributesTest extends BaseContainerTest +{ + /** + * @test + * @dataProvider provideContainer + */ + public function inject_in_properties(ContainerBuilder $builder) + { + $builder->useAttributes(true); + + /** @var B $object */ + $object = $builder->build()->get(B::class); + + $this->assertInstanceOf(A::class, $object->public); + $this->assertInstanceOf(A::class, $object->getProtected()); + $this->assertInstanceOf(A::class, $object->getPrivate()); + } + + /** + * Inject in parent properties (public, protected and private). + * + * @test + * @dataProvider provideContainer + */ + public function inject_in_parent_properties(ContainerBuilder $builder) + { + $builder->useAttributes(true); + $container = $builder->build(); + + /** @var C $object */ + $object = $container->get(C::class); + $this->assertInstanceOf(A::class, $object->public); + $this->assertInstanceOf(A::class, $object->getProtected()); + $this->assertInstanceOf(A::class, $object->getPrivate()); + + /** @var D $object */ + $object = $container->get(D::class); + $this->assertInstanceOf(A::class, $object->public); + $this->assertInstanceOf(A::class, $object->getProtected()); + $this->assertInstanceOf(A::class, $object->getPrivate()); + } + + /** + * Inject in private parent properties even if they have the same name of child properties. + * + * @test + * @dataProvider provideContainer + */ + public function inject_in_private_parent_properties_with_same_name(ContainerBuilder $builder) + { + $builder->useAttributes(true); + $container = $builder->build(); + + /** @var Child $object */ + $object = $container->get(Child::class); + $this->assertInstanceOf(A::class, $object->public); + $this->assertInstanceOf(A::class, $object->getProtected()); + $this->assertInstanceOf(A::class, $object->getPrivate()); + $this->assertInstanceOf(A::class, $object->getChildPrivate()); + } + + /** + * @test + * @dataProvider provideContainer + */ + public function inject_by_name(ContainerBuilder $builder) + { + $builder->useAttributes(true); + + $dependency = new \stdClass(); + + $builder->addDefinitions([ + 'namedDependency' => $dependency, + ]); + $container = $builder->build(); + + /** @var NamedInjection $object */ + $object = $container->get(NamedInjection::class); + $this->assertSame($dependency, $object->dependency1); + $this->assertSame($dependency, $object->dependency2); + } + + /** + * @test + * @dataProvider provideContainer + */ + public function errors_if_dependency_by_name_not_found(ContainerBuilder $builder) + { + $this->expectException(DependencyException::class); + $builder->useAttributes(true); + $builder->build()->get(NamedInjection::class); + } +} diff --git a/tests/IntegrationTest/Attributes/B.php b/tests/IntegrationTest/Attributes/B.php new file mode 100644 index 000000000..d4bbbfc25 --- /dev/null +++ b/tests/IntegrationTest/Attributes/B.php @@ -0,0 +1,29 @@ +protected; + } + + public function getPrivate() + { + return $this->private; + } +} diff --git a/tests/IntegrationTest/Attributes/C.php b/tests/IntegrationTest/Attributes/C.php new file mode 100644 index 000000000..e4eaf52c6 --- /dev/null +++ b/tests/IntegrationTest/Attributes/C.php @@ -0,0 +1,9 @@ +private; + } +} diff --git a/tests/IntegrationTest/Attributes/D.php b/tests/IntegrationTest/Attributes/D.php new file mode 100644 index 000000000..45a577d96 --- /dev/null +++ b/tests/IntegrationTest/Attributes/D.php @@ -0,0 +1,9 @@ += 8 + */ +class AttributeTest extends BaseContainerTest +{ + /** + * @dataProvider provideContainer + */ + public function test_injectable_annotation_is_not_required(ContainerBuilder $builder) + { + $container = $builder->useAttributes(true)->build(); + self::assertInstanceOf(NonAnnotatedClass::class, $container->get(NonAnnotatedClass::class)); + } + + /** + * @dataProvider provideContainer + */ + public function test_constructor_injection(ContainerBuilder $builder) + { + $builder->useAttributes(true); + $builder->addDefinitions([ + 'foo' => 'bar', + 'lazyService' => autowire(\stdClass::class)->lazy(), + ]); + $container = $builder->build(); + + $object = $container->get(ConstructorInjection::class); + + self::assertEquals(new \stdClass, $object->typedValue); + self::assertEquals(new \stdClass, $object->typedOptionalValue); + self::assertEquals('bar', $object->value); + self::assertInstanceOf(\stdClass::class, $object->lazyService); + self::assertInstanceOf(LazyLoadingInterface::class, $object->lazyService); + self::assertFalse($object->lazyService->isProxyInitialized()); + self::assertEquals('hello', $object->optionalValue); + } + + /** + * @dataProvider provideContainer + */ + public function test_property_injection(ContainerBuilder $builder) + { + $builder->useAttributes(true); + $builder->addDefinitions([ + 'foo' => 'bar', + 'lazyService' => autowire(\stdClass::class)->lazy(), + ]); + $container = $builder->build(); + + $object = $container->get(PropertyInjection::class); + + self::assertEquals('bar', $object->value); + self::assertEquals('bar', $object->value2); + self::assertInstanceOf(\stdClass::class, $object->entry); + self::assertInstanceOf(\stdClass::class, $object->lazyService); + self::assertInstanceOf(LazyLoadingInterface::class, $object->lazyService); + self::assertFalse($object->lazyService->isProxyInitialized()); + } + + /** + * @dataProvider provideContainer + */ + public function test_method_injection(ContainerBuilder $builder) + { + $builder->useAttributes(true); + $builder->addDefinitions([ + 'foo' => 'bar', + 'lazyService' => autowire(\stdClass::class)->lazy(), + ]); + $container = $builder->build(); + + $object = $container->get(ConstructorInjection::class); + + self::assertEquals(new \stdClass, $object->typedValue); + self::assertEquals(new \stdClass, $object->typedOptionalValue); + self::assertEquals('bar', $object->value); + self::assertInstanceOf(\stdClass::class, $object->lazyService); + self::assertInstanceOf(LazyLoadingInterface::class, $object->lazyService); + self::assertFalse($object->lazyService->isProxyInitialized()); + self::assertEquals('hello', $object->optionalValue); + } +} + +namespace DI\Test\IntegrationTest\Definitions\AttributesTest; + +use DI\Attribute\Inject; +use stdClass; + +class NonAnnotatedClass +{ +} + +class NamespacedClass +{ +} + +class ConstructorInjection +{ + public $value; + public $scalarValue; + public $typedValue; + public $typedOptionalValue; + /** @var \ProxyManager\Proxy\LazyLoadingInterface */ + public $lazyService; + public $optionalValue; + + #[Inject(['value' => 'foo', 'scalarValue' => 'foo', 'lazyService' => 'lazyService'])] + public function __construct( + $value, + string $scalarValue, + \stdClass $typedValue, + \stdClass $typedOptionalValue = null, + \stdClass $lazyService, + $optionalValue = 'hello' + ) { + $this->value = $value; + $this->scalarValue = $scalarValue; + $this->typedValue = $typedValue; + $this->typedOptionalValue = $typedOptionalValue; + $this->lazyService = $lazyService; + $this->optionalValue = $optionalValue; + } +} + +class PropertyInjection +{ + #[Inject(name: 'foo')] + public $value; + #[Inject('foo')] + public $value2; + #[Inject] + public stdClass $entry; + #[Inject('lazyService')] + public $lazyService; +} + +class MethodInjection +{ + public $value; + public $scalarValue; + public $typedValue; + public $typedOptionalValue; + /** @var \ProxyManager\Proxy\LazyLoadingInterface */ + public $lazyService; + public $optionalValue; + + #[Inject(['value' => 'foo', 'scalarValue' => 'foo', 'lazyService' => 'lazyService'])] + public function method( + $value, + string $scalarValue, + $untypedValue, + \stdClass $typedOptionalValue = null, + \stdClass $lazyService, + $optionalValue = 'hello' + ) { + $this->value = $value; + $this->scalarValue = $scalarValue; + $this->untypedValue = $untypedValue; + $this->typedOptionalValue = $typedOptionalValue; + $this->lazyService = $lazyService; + $this->optionalValue = $optionalValue; + } +} diff --git a/tests/UnitTest/Attributes/Fixtures/Dependency.php b/tests/UnitTest/Attributes/Fixtures/Dependency.php new file mode 100644 index 000000000..e90d65a3e --- /dev/null +++ b/tests/UnitTest/Attributes/Fixtures/Dependency.php @@ -0,0 +1,9 @@ + 'foo'])] + public function method3($str1) + { + } + + #[Inject(['str1' => []])] + public function method4($str1) + { + } +} diff --git a/tests/UnitTest/Attributes/Fixtures/Injectable1.php b/tests/UnitTest/Attributes/Fixtures/Injectable1.php new file mode 100644 index 000000000..75c3cb172 --- /dev/null +++ b/tests/UnitTest/Attributes/Fixtures/Injectable1.php @@ -0,0 +1,10 @@ += 8 + * + * @covers \DI\Attribute\Inject + */ +class InjectTest extends TestCase +{ + private ReflectionClass $reflectionClass; + + public function setUp(): void + { + $this->reflectionClass = new ReflectionClass(InjectFixture::class); + } + + public function testProperty1() + { + $property = $this->reflectionClass->getProperty('property1'); + /** @var Inject $annotation */ + $annotation = $property->getAttributes(Inject::class)[0]->newInstance(); + + $this->assertInstanceOf(Inject::class, $annotation); + $this->assertEquals('foo', $annotation->getName()); + } + + public function testProperty2() + { + $property = $this->reflectionClass->getProperty('property2'); + /** @var Inject $annotation */ + $annotation = $property->getAttributes(Inject::class)[0]->newInstance(); + + $this->assertInstanceOf(Inject::class, $annotation); + $this->assertNull($annotation->getName()); + } + + public function testProperty3() + { + $property = $this->reflectionClass->getProperty('property3'); + /** @var Inject $annotation */ + $annotation = $property->getAttributes(Inject::class)[0]->newInstance(); + + $this->assertInstanceOf(Inject::class, $annotation); + $this->assertEquals('foo', $annotation->getName()); + } + + public function testMethod1() + { + $method = $this->reflectionClass->getMethod('method1'); + /** @var Inject $annotation */ + $annotation = $method->getAttributes(Inject::class)[0]->newInstance(); + + $this->assertInstanceOf(Inject::class, $annotation); + $this->assertEmpty($annotation->getParameters()); + } + + public function testMethod2() + { + $method = $this->reflectionClass->getMethod('method2'); + /** @var Inject $annotation */ + $annotation = $method->getAttributes(Inject::class)[0]->newInstance(); + $parameters = $annotation->getParameters(); + + $this->assertInstanceOf(Inject::class, $annotation); + $this->assertCount(2, $parameters); + $this->assertEquals('foo', $parameters[0]); + $this->assertEquals('bar', $parameters[1]); + } + + public function testMethod3() + { + $method = $this->reflectionClass->getMethod('method3'); + /** @var Inject $annotation */ + $annotation = $method->getAttributes(Inject::class)[0]->newInstance(); + $parameters = $annotation->getParameters(); + + $this->assertInstanceOf(Inject::class, $annotation); + $this->assertCount(1, $parameters); + + $this->assertArrayHasKey('str1', $parameters); + $this->assertEquals('foo', $parameters['str1']); + } + + public function testInvalidAnnotation() + { + $this->expectException(InvalidAnnotation::class); + $this->expectExceptionMessage("#[Inject(['param' => 'value'])] expects \"value\" to be a string, [] given."); + $method = $this->reflectionClass->getMethod('method4'); + $method->getAttributes(Inject::class)[0]->newInstance(); + } +} diff --git a/tests/UnitTest/Attributes/InjectableTest.php b/tests/UnitTest/Attributes/InjectableTest.php new file mode 100644 index 000000000..aa2de42e9 --- /dev/null +++ b/tests/UnitTest/Attributes/InjectableTest.php @@ -0,0 +1,54 @@ += 8 + * + * @covers \DI\Annotation\Injectable + */ +class InjectableTest extends TestCase +{ + /** + * @var DoctrineAnnotationReader + */ + private $annotationReader; + + public function setUp(): void + { + $definitionReader = new AnnotationBasedAutowiring(); + $this->annotationReader = $definitionReader->getAnnotationReader(); + } + + public function testEmptyAnnotation() + { + $class = new ReflectionClass(Injectable1::class); + /** @var $annotation Injectable */ + $annotation = $this->annotationReader->getClassAnnotation($class, Injectable::class); + + $this->assertInstanceOf(Injectable::class, $annotation); + $this->assertNull($annotation->isLazy()); + } + + public function testLazy() + { + $class = new ReflectionClass(Injectable2::class); + /** @var $annotation Injectable */ + $annotation = $this->annotationReader->getClassAnnotation($class, Injectable::class); + + $this->assertInstanceOf(Injectable::class, $annotation); + $this->assertTrue($annotation->isLazy()); + } +} From b7d3d8f76de627850648e7f96a3bf29618746c09 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Mon, 5 Oct 2020 16:11:47 +0200 Subject: [PATCH 10/45] =?UTF-8?q?Fix=20PHP=208=20attributes=20=F0=9F=A4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Attribute/Injectable.php | 6 ++--- .../Source/AttributeBasedAutowiring.php | 16 ++++++----- .../Definitions/AttributeTest.php | 25 ++++++++++++++++- .../Attributes/Fixtures/Injectable1.php | 2 ++ .../Attributes/Fixtures/Injectable2.php | 2 ++ tests/UnitTest/Attributes/InjectableTest.php | 27 +++++-------------- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/Attribute/Injectable.php b/src/Attribute/Injectable.php index bc8acd12e..d52b268b9 100644 --- a/src/Attribute/Injectable.php +++ b/src/Attribute/Injectable.php @@ -24,11 +24,9 @@ final class Injectable */ private ?bool $lazy = null; - public function __construct(array $values) + public function __construct(?bool $lazy = null) { - if (isset($values['lazy'])) { - $this->lazy = (bool) $values['lazy']; - } + $this->lazy = $lazy; } public function isLazy() : ?bool diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php index 601b79291..73256d715 100644 --- a/src/Definition/Source/AttributeBasedAutowiring.php +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -187,11 +187,6 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection // Look for #[Inject] attribute try { $attribute = $method->getAttributes(Inject::class)[0] ?? null; - if (! $attribute) { - return null; - } - /** @var Inject $inject */ - $inject = $attribute->newInstance(); } catch (Throwable $e) { throw new InvalidAnnotation(sprintf( '#[Inject] annotation on %s::%s() is malformed. %s', @@ -201,7 +196,16 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection ), 0, $e); } - $annotationParameters = $inject->getParameters(); + if ($attribute) { + /** @var Inject $inject */ + $inject = $attribute->newInstance(); + $annotationParameters = $inject->getParameters(); + } elseif ($method->isConstructor()) { + // #[Inject] on constructor is implicit, we continue + $annotationParameters = []; + } else { + return null; + } $parameters = []; foreach ($method->getParameters() as $index => $parameter) { diff --git a/tests/IntegrationTest/Definitions/AttributeTest.php b/tests/IntegrationTest/Definitions/AttributeTest.php index 59b162a8c..7bdd67ca5 100644 --- a/tests/IntegrationTest/Definitions/AttributeTest.php +++ b/tests/IntegrationTest/Definitions/AttributeTest.php @@ -6,6 +6,7 @@ use DI\ContainerBuilder; use DI\Test\IntegrationTest\BaseContainerTest; +use DI\Test\IntegrationTest\Definitions\AttributesTest\AutowiredClass; use DI\Test\IntegrationTest\Definitions\AttributesTest\ConstructorInjection; use DI\Test\IntegrationTest\Definitions\AttributesTest\NonAnnotatedClass; use DI\Test\IntegrationTest\Definitions\AttributesTest\PropertyInjection; @@ -31,7 +32,7 @@ public function test_injectable_annotation_is_not_required(ContainerBuilder $bui /** * @dataProvider provideContainer */ - public function test_constructor_injection(ContainerBuilder $builder) + public function test_supports_autowiring(ContainerBuilder $builder) { $builder->useAttributes(true); $builder->addDefinitions([ @@ -51,6 +52,19 @@ public function test_constructor_injection(ContainerBuilder $builder) self::assertEquals('hello', $object->optionalValue); } + /** + * @dataProvider provideContainer + */ + public function test_constructor_injection(ContainerBuilder $builder) + { + $builder->useAttributes(true); + $container = $builder->build(); + + $object = $container->get(AutowiredClass::class); + + self::assertEquals(new \stdClass, $object->entry); + } + /** * @dataProvider provideContainer */ @@ -110,6 +124,15 @@ class NamespacedClass { } +class AutowiredClass +{ + public stdClass $entry; + public function __construct(stdClass $entry) + { + $this->entry = $entry; + } +} + class ConstructorInjection { public $value; diff --git a/tests/UnitTest/Attributes/Fixtures/Injectable1.php b/tests/UnitTest/Attributes/Fixtures/Injectable1.php index 75c3cb172..5d91d1ab0 100644 --- a/tests/UnitTest/Attributes/Fixtures/Injectable1.php +++ b/tests/UnitTest/Attributes/Fixtures/Injectable1.php @@ -4,6 +4,8 @@ namespace DI\Test\UnitTest\Attributes\Fixtures; +use DI\Attribute\Injectable; + #[Injectable] class Injectable1 { diff --git a/tests/UnitTest/Attributes/Fixtures/Injectable2.php b/tests/UnitTest/Attributes/Fixtures/Injectable2.php index 87c780280..34d4132f9 100644 --- a/tests/UnitTest/Attributes/Fixtures/Injectable2.php +++ b/tests/UnitTest/Attributes/Fixtures/Injectable2.php @@ -4,6 +4,8 @@ namespace DI\Test\UnitTest\Attributes\Fixtures; +use DI\Attribute\Injectable; + #[Injectable(lazy: true)] class Injectable2 { diff --git a/tests/UnitTest/Attributes/InjectableTest.php b/tests/UnitTest/Attributes/InjectableTest.php index aa2de42e9..988e8ce45 100644 --- a/tests/UnitTest/Attributes/InjectableTest.php +++ b/tests/UnitTest/Attributes/InjectableTest.php @@ -4,39 +4,26 @@ namespace DI\Test\UnitTest\Attributes; -use DI\Annotation\Injectable; -use DI\Definition\Source\AnnotationBasedAutowiring; +use DI\Attribute\Injectable; use DI\Test\UnitTest\Attributes\Fixtures\Injectable1; use DI\Test\UnitTest\Attributes\Fixtures\Injectable2; -use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader; use PHPUnit\Framework\TestCase; use ReflectionClass; /** - * Injectable annotation test class. + * Injectable attribute test class. * * @requires PHP >= 8 * - * @covers \DI\Annotation\Injectable + * @covers \DI\Attribute\Injectable */ class InjectableTest extends TestCase { - /** - * @var DoctrineAnnotationReader - */ - private $annotationReader; - - public function setUp(): void - { - $definitionReader = new AnnotationBasedAutowiring(); - $this->annotationReader = $definitionReader->getAnnotationReader(); - } - public function testEmptyAnnotation() { $class = new ReflectionClass(Injectable1::class); - /** @var $annotation Injectable */ - $annotation = $this->annotationReader->getClassAnnotation($class, Injectable::class); + /** @var Injectable $annotation */ + $annotation = $class->getAttributes(Injectable::class)[0]->newInstance(); $this->assertInstanceOf(Injectable::class, $annotation); $this->assertNull($annotation->isLazy()); @@ -45,8 +32,8 @@ public function testEmptyAnnotation() public function testLazy() { $class = new ReflectionClass(Injectable2::class); - /** @var $annotation Injectable */ - $annotation = $this->annotationReader->getClassAnnotation($class, Injectable::class); + /** @var Injectable $annotation */ + $annotation = $class->getAttributes(Injectable::class)[0]->newInstance(); $this->assertInstanceOf(Injectable::class, $annotation); $this->assertTrue($annotation->isLazy()); From 0ea9d81ab03f2c8c4d5a8441923377b64fefd500 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Mon, 12 Oct 2020 16:46:17 +0200 Subject: [PATCH 11/45] Update CI for v7 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 647c31b06..f7598e828 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,10 +16,10 @@ jobs: timeout-minutes: 15 strategy: matrix: - php: [ '7.2', '7.3', '7.4', '8.0' ] + php: [ '7.4', '8.0' ] dependency-version: [ '' ] include: - - php: '7.2' + - php: '7.4' dependency-version: '--prefer-lowest' steps: - name: Checkout From 2a8bb30ad2957aa138784cc4e454c8be3851b3cf Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Thu, 22 Oct 2020 21:16:11 +0200 Subject: [PATCH 12/45] Support PHP 8 attributes at the parameter level --- doc/attributes.md | 24 +++++++++++---- src/Attribute/Inject.php | 2 +- .../Source/AttributeBasedAutowiring.php | 22 ++++++-------- .../Definitions/AttributeTest.php | 29 ++++++++++++++----- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/doc/attributes.md b/doc/attributes.md index 8a8bbcf59..94a084c3f 100644 --- a/doc/attributes.md +++ b/doc/attributes.md @@ -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) { } @@ -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) { } } diff --git a/src/Attribute/Inject.php b/src/Attribute/Inject.php index 5a6de250d..51c6005b0 100644 --- a/src/Attribute/Inject.php +++ b/src/Attribute/Inject.php @@ -16,7 +16,7 @@ * * @author Matthieu Napoli */ -#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)] +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)] final class Inject { /** diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php index 73256d715..5466a2c18 100644 --- a/src/Definition/Source/AttributeBasedAutowiring.php +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -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 */ @@ -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]; diff --git a/tests/IntegrationTest/Definitions/AttributeTest.php b/tests/IntegrationTest/Definitions/AttributeTest.php index 7bdd67ca5..039672f20 100644 --- a/tests/IntegrationTest/Definitions/AttributeTest.php +++ b/tests/IntegrationTest/Definitions/AttributeTest.php @@ -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. @@ -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(); @@ -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(); @@ -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(); @@ -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); } } @@ -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( @@ -150,13 +156,16 @@ public function __construct( \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; } } @@ -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'])] @@ -190,6 +200,8 @@ public function method( $untypedValue, \stdClass $typedOptionalValue = null, \stdClass $lazyService, + #[Inject('attribute')] + stdClass $attribute, $optionalValue = 'hello' ) { $this->value = $value; @@ -197,6 +209,7 @@ public function method( $this->untypedValue = $untypedValue; $this->typedOptionalValue = $typedOptionalValue; $this->lazyService = $lazyService; + $this->attribute = $attribute; $this->optionalValue = $optionalValue; } } From a1be38dbc4bd51500977e22865644ab9b369d49f Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 27 Feb 2021 17:57:07 +0100 Subject: [PATCH 13/45] Test and document using PHP 8 named arguments for config --- doc/php-definitions.md | 14 +++++++++ .../Definitions/AutowireDefinitionTest.php | 30 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/doc/php-definitions.md b/doc/php-definitions.md index 0daa8b471..4e21175ae 100644 --- a/doc/php-definitions.md +++ b/doc/php-definitions.md @@ -357,6 +357,20 @@ return [ ]; ``` +Since PHP 8, you can also use [named arguments](https://stitcher.io/blog/php-8-named-arguments): + +```php +return [ + 'Logger' => DI\autowire() + // set the $filename parameter + ->constructor( + filename: 'app.log' + ) + // set the $handler parameter + ->method('setHandler', handler: DI\get('SyslogHandler')), +]; +``` + ### Aliases You can alias an entry to another using the `DI\get()` helper: diff --git a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php index ef95bef9d..bda1c048b 100644 --- a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php @@ -68,6 +68,23 @@ public function test_constructor_injection(ContainerBuilder $builder) self::assertEquals('hello', $object->optionalValue); } + /** + * @dataProvider provideContainer + */ + public function test_constructor_injection_with_named_arguments(ContainerBuilder $builder) + { + $builder->addDefinitions([ + ConstructorInjection::class => autowire() + ->constructor( + value: 'bar', + ), + ]); + $container = $builder->build(); + + $object = $container->get(ConstructorInjection::class); + self::assertEquals('bar', $object->value); + } + /** * @dataProvider provideContainer */ @@ -246,6 +263,19 @@ public function test_setting_specific_method_parameter(ContainerBuilder $builder self::assertEquals('Hello', $container->get(Setter::class)->bar); } + /** + * @dataProvider provideContainer + */ + public function test_setting_specific_method_parameter_with_named_arguments(ContainerBuilder $builder) + { + $container = $builder->addDefinitions([ + Setter::class => autowire() + ->method('setFoo', bar: 'Hello'), + ])->build(); + + self::assertEquals('Hello', $container->get(Setter::class)->bar); + } + /** * @dataProvider provideContainer */ From b6de725c16e99791ed430387eeb9e25419680121 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 27 Feb 2021 19:09:59 +0100 Subject: [PATCH 14/45] Require PHP 8.0 and use stricter types/fix warnings --- psalm.xml | 15 ++++++ src/Annotation/Inject.php | 2 +- src/Annotation/Injectable.php | 2 +- src/Attribute/Inject.php | 6 +-- src/Attribute/Injectable.php | 12 ++--- src/CompiledContainer.php | 36 +++++++------- src/Compiler/Compiler.php | 12 ++--- src/Compiler/ObjectCreationCompiler.php | 15 +++--- src/Compiler/RequestedEntryHolder.php | 10 ++-- src/Container.php | 49 +++++++++---------- src/ContainerBuilder.php | 10 +--- src/Definition/ArrayDefinition.php | 14 ++---- src/Definition/DecoratorDefinition.php | 2 +- src/Definition/Definition.php | 4 +- .../Dumper/ObjectDefinitionDumper.php | 2 +- .../EnvironmentVariableDefinition.php | 39 ++++----------- src/Definition/FactoryDefinition.php | 10 ++-- .../Helper/AutowireDefinitionHelper.php | 4 +- .../Helper/CreateDefinitionHelper.php | 4 +- .../Helper/FactoryDefinitionHelper.php | 6 +-- src/Definition/InstanceDefinition.php | 16 +++--- src/Definition/ObjectDefinition.php | 12 ++--- .../ObjectDefinition/MethodInjection.php | 22 ++++----- .../ObjectDefinition/PropertyInjection.php | 7 ++- src/Definition/Reference.php | 19 +++---- src/Definition/Resolver/ArrayResolver.php | 10 ++-- src/Definition/Resolver/DecoratorResolver.php | 16 +++--- .../Resolver/DefinitionResolver.php | 2 +- .../Resolver/EnvironmentVariableResolver.php | 17 ++----- src/Definition/Resolver/FactoryResolver.php | 14 ++---- src/Definition/Resolver/ObjectCreator.php | 17 +++---- src/Definition/Resolver/ParameterResolver.php | 17 +++---- .../Resolver/ResolverDispatcher.php | 16 +++--- src/Definition/SelfResolvingDefinition.php | 4 +- .../Source/AnnotationBasedAutowiring.php | 24 +++++---- .../Source/AttributeBasedAutowiring.php | 12 ++--- src/Definition/Source/Autowiring.php | 3 +- src/Definition/Source/DefinitionArray.php | 41 ++++++---------- src/Definition/Source/DefinitionFile.php | 25 ++++------ .../Source/DefinitionNormalizer.php | 19 ++----- src/Definition/Source/DefinitionSource.php | 3 +- .../Source/MutableDefinitionSource.php | 2 +- src/Definition/Source/NoAutowiring.php | 2 +- .../Source/ReflectionBasedAutowiring.php | 12 ++--- src/Definition/Source/SourceCache.php | 27 +++------- src/Definition/Source/SourceChain.php | 23 +++------ src/Definition/StringDefinition.php | 14 ++---- src/Definition/ValueDefinition.php | 23 +++------ src/FactoryInterface.php | 3 +- src/Invoker/DefinitionParameterResolver.php | 8 ++- src/Invoker/FactoryParameterResolver.php | 8 ++- src/functions.php | 14 +++--- .../Definitions/AutowireDefinitionTest.php | 14 ------ .../ErrorMessages/ErrorMessagesTest.php | 14 ------ tests/UnitTest/ContainerBuilderTest.php | 11 ----- 55 files changed, 269 insertions(+), 476 deletions(-) create mode 100644 psalm.xml diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 000000000..30258a709 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/src/Annotation/Inject.php b/src/Annotation/Inject.php index dc69d646a..cc3f7d550 100644 --- a/src/Annotation/Inject.php +++ b/src/Annotation/Inject.php @@ -76,7 +76,7 @@ public function __construct(array $values) /** * @return string|null Name of the entry to inject */ - public function getName() : ?string + public function getName() : string|null { return $this->name; } diff --git a/src/Annotation/Injectable.php b/src/Annotation/Injectable.php index 96e4b69f2..ddab369bc 100644 --- a/src/Annotation/Injectable.php +++ b/src/Annotation/Injectable.php @@ -31,7 +31,7 @@ public function __construct(array $values) } } - public function isLazy() : ?bool + public function isLazy() : bool|null { return $this->lazy; } diff --git a/src/Attribute/Inject.php b/src/Attribute/Inject.php index 51c6005b0..74ca4fd16 100644 --- a/src/Attribute/Inject.php +++ b/src/Attribute/Inject.php @@ -32,11 +32,9 @@ final class Inject private array $parameters = []; /** - * @param string|array|null $name - * * @throws InvalidAnnotation */ - public function __construct($name = null) + public function __construct(string|array|null $name = null) { // #[Inject('foo')] or #[Inject(name: 'foo')] if (is_string($name)) { @@ -61,7 +59,7 @@ public function __construct($name = null) /** * @return string|null Name of the entry to inject */ - public function getName() : ?string + public function getName() : string|null { return $this->name; } diff --git a/src/Attribute/Injectable.php b/src/Attribute/Injectable.php index d52b268b9..2acb78326 100644 --- a/src/Attribute/Injectable.php +++ b/src/Attribute/Injectable.php @@ -20,16 +20,14 @@ final class Injectable { /** - * Should the object be lazy-loaded. + * @param bool|null $lazy Should the object be lazy-loaded. */ - private ?bool $lazy = null; - - public function __construct(?bool $lazy = null) - { - $this->lazy = $lazy; + public function __construct( + private ?bool $lazy = null, + ) { } - public function isLazy() : ?bool + public function isLazy() : bool|null { return $this->lazy; } diff --git a/src/CompiledContainer.php b/src/CompiledContainer.php index 30f1ce81c..1fc6d5605 100644 --- a/src/CompiledContainer.php +++ b/src/CompiledContainer.php @@ -29,59 +29,59 @@ abstract class CompiledContainer extends Container /** * {@inheritdoc} */ - public function get($name) + public function get($id): mixed { // Try to find the entry in the singleton map - if (isset($this->resolvedEntries[$name]) || array_key_exists($name, $this->resolvedEntries)) { - return $this->resolvedEntries[$name]; + if (isset($this->resolvedEntries[$id]) || array_key_exists($id, $this->resolvedEntries)) { + return $this->resolvedEntries[$id]; } - $method = static::METHOD_MAPPING[$name] ?? null; + $method = static::METHOD_MAPPING[$id] ?? null; // If it's a compiled entry, then there is a method in this class if ($method !== null) { // Check if we are already getting this entry -> circular dependency - if (isset($this->entriesBeingResolved[$name])) { - throw new DependencyException("Circular dependency detected while trying to resolve entry '$name'"); + if (isset($this->entriesBeingResolved[$id])) { + throw new DependencyException("Circular dependency detected while trying to resolve entry '$id'"); } - $this->entriesBeingResolved[$name] = true; + $this->entriesBeingResolved[$id] = true; try { $value = $this->$method(); } finally { - unset($this->entriesBeingResolved[$name]); + unset($this->entriesBeingResolved[$id]); } // Store the entry to always return it without recomputing it - $this->resolvedEntries[$name] = $value; + $this->resolvedEntries[$id] = $value; return $value; } - return parent::get($name); + return parent::get($id); } /** * {@inheritdoc} */ - public function has($name) : bool + public function has($id): bool { - if (! is_string($name)) { + if (! is_string($id)) { throw new \InvalidArgumentException(sprintf( 'The name parameter must be of type string, %s given', - is_object($name) ? get_class($name) : gettype($name) + is_object($id) ? get_class($id) : gettype($id) )); } // The parent method is overridden to check in our array, it avoids resolving definitions - if (isset(static::METHOD_MAPPING[$name])) { + if (isset(static::METHOD_MAPPING[$id])) { return true; } - return parent::has($name); + return parent::has($id); } - protected function setDefinition(string $name, Definition $definition) : void + protected function setDefinition(string $name, Definition $definition): void { // It needs to be forbidden because that would mean get() must go through the definitions // every time, which kinds of defeats the performance gains of the compiled container @@ -90,10 +90,8 @@ protected function setDefinition(string $name, Definition $definition) : void /** * Invoke the given callable. - * - * @return mixed */ - protected function resolveFactory($callable, $entryName, array $extraParameters = []) + protected function resolveFactory($callable, $entryName, array $extraParameters = []): mixed { // Initialize the factory resolver if (! $this->factoryInvoker) { diff --git a/src/Compiler/Compiler.php b/src/Compiler/Compiler.php index cc051b1da..7cba94022 100644 --- a/src/Compiler/Compiler.php +++ b/src/Compiler/Compiler.php @@ -77,11 +77,9 @@ class Compiler private bool $autowiringEnabled; - private ProxyFactory $proxyFactory; - - public function __construct(ProxyFactory $proxyFactory) - { - $this->proxyFactory = $proxyFactory; + public function __construct( + private ProxyFactory $proxyFactory, + ) { } public function getProxyFactory() : ProxyFactory @@ -302,7 +300,7 @@ private function compileDefinition(string $entryName, Definition $definition) : return $methodName; } - public function compileValue($value) : string + public function compileValue(mixed $value) : string { // Check that the value can be compiled $errorMessage = $this->isCompilable($value); @@ -351,7 +349,7 @@ private function createCompilationDirectory(string $directory) : void /** * @return string|true If true is returned that means that the value is compilable. */ - private function isCompilable($value) + private function isCompilable($value): string|bool { if ($value instanceof ValueDefinition) { return $this->isCompilable($value->getValue()); diff --git a/src/Compiler/ObjectCreationCompiler.php b/src/Compiler/ObjectCreationCompiler.php index 138cb2d34..685641fc7 100644 --- a/src/Compiler/ObjectCreationCompiler.php +++ b/src/Compiler/ObjectCreationCompiler.php @@ -19,11 +19,9 @@ */ class ObjectCreationCompiler { - private Compiler $compiler; - - public function __construct(Compiler $compiler) - { - $this->compiler = $compiler; + public function __construct( + private Compiler $compiler, + ) { } public function compile(ObjectDefinition $definition) : string @@ -96,7 +94,7 @@ public function compile(ObjectDefinition $definition) : string return implode("\n ", $code); } - public function resolveParameters(MethodInjection $definition = null, ReflectionMethod $method = null) : array + public function resolveParameters(?MethodInjection $definition, ?ReflectionMethod $method) : array { $args = []; @@ -152,9 +150,8 @@ function (&\$wrappedObject, \$proxy, \$method, \$params, &\$initializer) { * Returns the default value of a function parameter. * * @throws InvalidDefinition Can't get default values from PHP internal classes and functions - * @return mixed */ - private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function) + private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function): mixed { try { return $parameter->getDefaultValue(); @@ -175,7 +172,7 @@ private function getFunctionName(ReflectionMethod $method) : string private function assertClassIsNotAnonymous(ObjectDefinition $definition) : void { - if (strpos($definition->getClassName(), '@') !== false) { + if (str_contains($definition->getClassName(), '@')) { throw InvalidDefinition::create($definition, sprintf( 'Entry "%s" cannot be compiled: anonymous classes cannot be compiled', $definition->getName() diff --git a/src/Compiler/RequestedEntryHolder.php b/src/Compiler/RequestedEntryHolder.php index a84cddf40..04d407505 100644 --- a/src/Compiler/RequestedEntryHolder.php +++ b/src/Compiler/RequestedEntryHolder.php @@ -11,14 +11,12 @@ */ class RequestedEntryHolder implements RequestedEntry { - private string $name; - - public function __construct(string $name) - { - $this->name = $name; + public function __construct( + private string $name, + ) { } - public function getName() : string + public function getName(): string { return $this->name; } diff --git a/src/Container.php b/src/Container.php index c385c28e1..a49a8a305 100644 --- a/src/Container.php +++ b/src/Container.php @@ -101,32 +101,31 @@ public function __construct( /** * Returns an entry of the container by its name. * - * @param string $name Entry name or a class name. + * @param string $id Entry name or a class name. * * @throws DependencyException Error while resolving the entry. * @throws NotFoundException No entry found for the given name. - * @return mixed */ - public function get($name) + public function get($id): mixed { // If the entry is already resolved we return it - if (isset($this->resolvedEntries[$name]) || array_key_exists($name, $this->resolvedEntries)) { - return $this->resolvedEntries[$name]; + if (isset($this->resolvedEntries[$id]) || array_key_exists($id, $this->resolvedEntries)) { + return $this->resolvedEntries[$id]; } - $definition = $this->getDefinition($name); + $definition = $this->getDefinition($id); if (! $definition) { - throw new NotFoundException("No entry or class found for '$name'"); + throw new NotFoundException("No entry or class found for '$id'"); } $value = $this->resolveDefinition($definition); - $this->resolvedEntries[$name] = $value; + $this->resolvedEntries[$id] = $value; return $value; } - private function getDefinition(string $name) : ?Definition + private function getDefinition(string $name): ?Definition { // Local cache that avoids fetching the same definition twice if (!array_key_exists($name, $this->fetchedDefinitions)) { @@ -152,9 +151,8 @@ private function getDefinition(string $name) : ?Definition * @throws InvalidArgumentException The name parameter must be of type string. * @throws DependencyException Error while resolving the entry. * @throws NotFoundException No entry found for the given name. - * @return mixed */ - public function make(string $name, array $parameters = []) + public function make(string $name, array $parameters = []): mixed { if (! is_string($name)) { throw new InvalidArgumentException(sprintf( @@ -179,24 +177,24 @@ public function make(string $name, array $parameters = []) /** * Test if the container can provide something for the given name. * - * @param string $name Entry name or a class name. + * @param string $id Entry name or a class name. * * @throws InvalidArgumentException The name parameter must be of type string. */ - public function has($name) : bool + public function has($id) : bool { - if (! is_string($name)) { + if (! is_string($id)) { throw new InvalidArgumentException(sprintf( 'The name parameter must be of type string, %s given', - is_object($name) ? get_class($name) : gettype($name) + is_object($id) ? get_class($id) : gettype($id) )); } - if (array_key_exists($name, $this->resolvedEntries)) { + if (array_key_exists($id, $this->resolvedEntries)) { return true; } - $definition = $this->getDefinition($name); + $definition = $this->getDefinition($id); if ($definition === null) { return false; } @@ -214,11 +212,11 @@ public function has($name) : bool */ public function injectOn(object $instance) : object { - $className = get_class($instance); + $className = $instance::class; // If the class is anonymous, don't cache its definition // Checking for anonymous classes is cleaner via Reflection, but also slower - $objectDefinition = false !== strpos($className, '@anonymous') + $objectDefinition = str_contains($className, '@anonymous') ? $this->definitionSource->getDefinition($className) : $this->getDefinition($className); @@ -238,14 +236,14 @@ public function injectOn(object $instance) : object * * Missing parameters will be resolved from the container. * - * @param callable $callable Function to call. + * @param callable|array|string $callable Function to call. * @param array $parameters Parameters to use. Can be indexed by the parameter names * or not indexed (same order as the parameters). * The array can also contain DI definitions, e.g. DI\get(). * * @return mixed Result of the function. */ - public function call($callable, array $parameters = []) + public function call($callable, array $parameters = []): mixed { return $this->getInvoker()->call($callable, $parameters); } @@ -256,7 +254,7 @@ public function call($callable, array $parameters = []) * @param string $name Entry name * @param mixed|DefinitionHelper $value Value, use definition helpers to define objects */ - public function set(string $name, $value) + public function set(string $name, mixed $value): void { if ($value instanceof DefinitionHelper) { $value = $value->getDefinition($name); @@ -314,10 +312,8 @@ public function debugEntry(string $name) : string /** * Get formatted entry type. - * - * @param mixed $entry */ - private function getEntryType($entry) : string + private function getEntryType(mixed $entry) : string { if (is_object($entry)) { return sprintf("Object (\n class = %s\n)", get_class($entry)); @@ -344,9 +340,8 @@ private function getEntryType($entry) : string * Checks for circular dependencies while resolving the definition. * * @throws DependencyException Error while resolving the entry. - * @return mixed */ - private function resolveDefinition(Definition $definition, array $parameters = []) + private function resolveDefinition(Definition $definition, array $parameters = []): mixed { $entryName = $definition->getName(); diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index c1b695ffc..e0a305a70 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -302,19 +302,11 @@ public function wrapContainer(ContainerInterface $otherContainer) : self * or a DefinitionSource object. * @return $this */ - public function addDefinitions(...$definitions) : self + public function addDefinitions(string|array|DefinitionSource ...$definitions) : self { $this->ensureNotLocked(); foreach ($definitions as $definition) { - if (!is_string($definition) && !is_array($definition) && !($definition instanceof DefinitionSource)) { - throw new InvalidArgumentException(sprintf( - '%s parameter must be a string, an array or a DefinitionSource object, %s given', - 'ContainerBuilder::addDefinitions()', - is_object($definition) ? get_class($definition) : gettype($definition) - )); - } - $this->definitionSources[] = $definition; } diff --git a/src/Definition/ArrayDefinition.php b/src/Definition/ArrayDefinition.php index db1b1f018..81c381138 100644 --- a/src/Definition/ArrayDefinition.php +++ b/src/Definition/ArrayDefinition.php @@ -12,16 +12,12 @@ */ class ArrayDefinition implements Definition { - /** - * Entry name. - */ + /** Entry name. */ private string $name = ''; - private array $values; - - public function __construct(array $values) - { - $this->values = $values; + public function __construct( + private array $values, + ) { } public function getName() : string @@ -44,7 +40,7 @@ public function replaceNestedDefinitions(callable $replacer) : void $this->values = array_map($replacer, $this->values); } - public function __toString() + public function __toString(): string { $str = '[' . PHP_EOL; diff --git a/src/Definition/DecoratorDefinition.php b/src/Definition/DecoratorDefinition.php index 32d859977..cdbfb72d1 100644 --- a/src/Definition/DecoratorDefinition.php +++ b/src/Definition/DecoratorDefinition.php @@ -29,7 +29,7 @@ public function replaceNestedDefinitions(callable $replacer) : void // no nested definitions } - public function __toString() + public function __toString(): string { return 'Decorate(' . $this->getName() . ')'; } diff --git a/src/Definition/Definition.php b/src/Definition/Definition.php index 5cf4caa1f..ab19087e6 100644 --- a/src/Definition/Definition.php +++ b/src/Definition/Definition.php @@ -13,7 +13,7 @@ * * @author Matthieu Napoli */ -interface Definition extends RequestedEntry +interface Definition extends RequestedEntry, \Stringable { /** * Returns the name of the entry in the container. @@ -33,5 +33,5 @@ public function replaceNestedDefinitions(callable $replacer) : void; /** * Definitions can be cast to string for debugging information. */ - public function __toString(); + public function __toString(): string; } diff --git a/src/Definition/Dumper/ObjectDefinitionDumper.php b/src/Definition/Dumper/ObjectDefinitionDumper.php index 7e1999961..8600a5cd5 100644 --- a/src/Definition/Dumper/ObjectDefinitionDumper.php +++ b/src/Definition/Dumper/ObjectDefinitionDumper.php @@ -122,7 +122,7 @@ private function dumpMethodParameters(string $className, MethodInjection $method var_export($value, true) ); continue; - } catch (ReflectionException $e) { + } catch (ReflectionException) { // The default value can't be read through Reflection because it is a PHP internal class } } diff --git a/src/Definition/EnvironmentVariableDefinition.php b/src/Definition/EnvironmentVariableDefinition.php index 913c04d5d..cd17445c5 100644 --- a/src/Definition/EnvironmentVariableDefinition.php +++ b/src/Definition/EnvironmentVariableDefinition.php @@ -12,40 +12,19 @@ */ class EnvironmentVariableDefinition implements Definition { - /** - * Entry name. - */ + /** Entry name. */ private string $name = ''; - /** - * The name of the environment variable. - */ - private string $variableName; - - /** - * Whether or not the environment variable definition is optional. - * - * If true and the environment variable given by $variableName has not been - * defined, $defaultValue is used. - */ - private bool $isOptional; - - /** - * The default value to use if the environment variable is optional and not provided. - * @var mixed - */ - private $defaultValue; - /** * @param string $variableName The name of the environment variable - * @param bool $isOptional Whether or not the environment variable definition is optional + * @param bool $isOptional Whether or not the environment variable definition is optional. If true and the environment variable given by $variableName has not been defined, $defaultValue is used. * @param mixed $defaultValue The default value to use if the environment variable is optional and not provided */ - public function __construct(string $variableName, bool $isOptional = false, $defaultValue = null) - { - $this->variableName = $variableName; - $this->isOptional = $isOptional; - $this->defaultValue = $defaultValue; + public function __construct( + private string $variableName, + private bool $isOptional = false, + private mixed $defaultValue = null, + ) { } public function getName() : string @@ -77,7 +56,7 @@ public function isOptional() : bool /** * @return mixed The default value to use if the environment variable is optional and not provided */ - public function getDefaultValue() + public function getDefaultValue(): mixed { return $this->defaultValue; } @@ -87,7 +66,7 @@ public function replaceNestedDefinitions(callable $replacer) : void $this->defaultValue = $replacer($this->defaultValue); } - public function __toString() + public function __toString(): string { $str = ' variable = ' . $this->variableName . PHP_EOL . ' optional = ' . ($this->isOptional ? 'yes' : 'no'); diff --git a/src/Definition/FactoryDefinition.php b/src/Definition/FactoryDefinition.php index 47c8da734..e027f571f 100644 --- a/src/Definition/FactoryDefinition.php +++ b/src/Definition/FactoryDefinition.php @@ -30,10 +30,10 @@ class FactoryDefinition implements Definition /** * @param string $name Entry name - * @param callable $factory Callable that returns the value associated to the entry name. + * @param callable|array|string $factory Callable that returns the value associated to the entry name. * @param array $parameters Parameters to be passed to the callable */ - public function __construct(string $name, $factory, array $parameters = []) + public function __construct(string $name, callable|array|string $factory, array $parameters = []) { $this->name = $name; $this->factory = $factory; @@ -51,9 +51,9 @@ public function setName(string $name) : void } /** - * @return callable Callable that returns the value associated to the entry name. + * @return callable|array|string Callable that returns the value associated to the entry name. */ - public function getCallable() + public function getCallable(): callable|array|string { return $this->factory; } @@ -71,7 +71,7 @@ public function replaceNestedDefinitions(callable $replacer) : void $this->parameters = array_map($replacer, $this->parameters); } - public function __toString() + public function __toString(): string { return 'Factory'; } diff --git a/src/Definition/Helper/AutowireDefinitionHelper.php b/src/Definition/Helper/AutowireDefinitionHelper.php index 905e3f939..7d548672c 100644 --- a/src/Definition/Helper/AutowireDefinitionHelper.php +++ b/src/Definition/Helper/AutowireDefinitionHelper.php @@ -28,7 +28,7 @@ class AutowireDefinitionHelper extends CreateDefinitionHelper * * @return $this */ - public function constructorParameter($parameter, $value) : self + public function constructorParameter(string|int $parameter, mixed $value) : self { $this->constructor[$parameter] = $value; @@ -52,7 +52,7 @@ public function constructorParameter($parameter, $value) : self * * @return $this */ - public function methodParameter(string $method, $parameter, $value) : self + public function methodParameter(string $method, string|int $parameter, mixed $value) : self { // Special case for the constructor if ($method === '__construct') { diff --git a/src/Definition/Helper/CreateDefinitionHelper.php b/src/Definition/Helper/CreateDefinitionHelper.php index 90c1b439b..c2a4fa861 100644 --- a/src/Definition/Helper/CreateDefinitionHelper.php +++ b/src/Definition/Helper/CreateDefinitionHelper.php @@ -87,7 +87,7 @@ public function constructor(...$parameters) : self * * @return $this */ - public function property(string $property, $value) : self + public function property(string $property, mixed $value) : self { $this->properties[$property] = $value; @@ -108,7 +108,7 @@ public function property(string $property, $value) : self * * @return $this */ - public function method(string $method, ...$parameters) : self + public function method(string $method, mixed ...$parameters) : self { if (! isset($this->methods[$method])) { $this->methods[$method] = []; diff --git a/src/Definition/Helper/FactoryDefinitionHelper.php b/src/Definition/Helper/FactoryDefinitionHelper.php index 09774db9d..a6906c85a 100644 --- a/src/Definition/Helper/FactoryDefinitionHelper.php +++ b/src/Definition/Helper/FactoryDefinitionHelper.php @@ -5,7 +5,6 @@ namespace DI\Definition\Helper; use DI\Definition\DecoratorDefinition; -use DI\Definition\Definition; use DI\Definition\FactoryDefinition; /** @@ -25,10 +24,9 @@ class FactoryDefinitionHelper implements DefinitionHelper private array $parameters = []; /** - * @param callable $factory * @param bool $decorate Is the factory decorating a previous definition? */ - public function __construct($factory, bool $decorate = false) + public function __construct(callable|array|string $factory, bool $decorate = false) { $this->factory = $factory; $this->decorate = $decorate; @@ -56,7 +54,7 @@ public function getDefinition(string $entryName) : FactoryDefinition * * @return $this */ - public function parameter(string $parameter, $value) : self + public function parameter(string $parameter, mixed $value) : self { $this->parameters[$parameter] = $value; diff --git a/src/Definition/InstanceDefinition.php b/src/Definition/InstanceDefinition.php index b5ea573df..bc1abe535 100644 --- a/src/Definition/InstanceDefinition.php +++ b/src/Definition/InstanceDefinition.php @@ -13,16 +13,12 @@ class InstanceDefinition implements Definition { /** - * Instance on which to inject dependencies. + * @param object $instance Instance on which to inject dependencies. */ - private object $instance; - - private ObjectDefinition $objectDefinition; - - public function __construct(object $instance, ObjectDefinition $objectDefinition) - { - $this->instance = $instance; - $this->objectDefinition = $objectDefinition; + public function __construct( + private object $instance, + private ObjectDefinition $objectDefinition, + ) { } public function getName() : string @@ -51,7 +47,7 @@ public function replaceNestedDefinitions(callable $replacer) : void $this->objectDefinition->replaceNestedDefinitions($replacer); } - public function __toString() + public function __toString(): string { return 'Instance'; } diff --git a/src/Definition/ObjectDefinition.php b/src/Definition/ObjectDefinition.php index c116b8247..458ed50ce 100644 --- a/src/Definition/ObjectDefinition.php +++ b/src/Definition/ObjectDefinition.php @@ -68,7 +68,7 @@ public function setName(string $name) : void $this->name = $name; } - public function setClassName(string $className = null) + public function setClassName(?string $className): void { $this->className = $className; @@ -77,11 +77,7 @@ public function setClassName(string $className = null) public function getClassName() : string { - if ($this->className !== null) { - return $this->className; - } - - return $this->name; + return $this->className ?? $this->name; } public function getConstructorInjection() : ?MethodInjection @@ -209,7 +205,7 @@ public function replaceNestedDefinitions(callable $replacer) : void * * @param string[] $replacements */ - public function replaceWildcards(array $replacements) + public function replaceWildcards(array $replacements): void { $className = $this->getClassName(); @@ -223,7 +219,7 @@ public function replaceWildcards(array $replacements) $this->setClassName($className); } - public function __toString() + public function __toString(): string { return (new ObjectDefinitionDumper)->dump($this); } diff --git a/src/Definition/ObjectDefinition/MethodInjection.php b/src/Definition/ObjectDefinition/MethodInjection.php index d88b1c1a2..a6c393c17 100644 --- a/src/Definition/ObjectDefinition/MethodInjection.php +++ b/src/Definition/ObjectDefinition/MethodInjection.php @@ -13,17 +13,13 @@ */ class MethodInjection implements Definition { - private string $methodName; - /** - * @var mixed[] + * @param mixed[] $parameters */ - private array $parameters; - - public function __construct(string $methodName, array $parameters = []) - { - $this->methodName = $methodName; - $this->parameters = $parameters; + public function __construct( + private string $methodName, + private array $parameters = [], + ) { } public static function constructor(array $parameters = []) : self @@ -47,15 +43,15 @@ public function getParameters() : array /** * Replace the parameters of the definition by a new array of parameters. */ - public function replaceParameters(array $parameters) + public function replaceParameters(array $parameters): void { $this->parameters = $parameters; } - public function merge(self $definition) + public function merge(self $definition): void { // In case of conflicts, the current definition prevails. - $this->parameters = $this->parameters + $definition->parameters; + $this->parameters += $definition->parameters; } public function getName() : string @@ -76,7 +72,7 @@ public function replaceNestedDefinitions(callable $replacer) : void /** * {@inheritdoc} */ - public function __toString() + public function __toString(): string { return sprintf('method(%s)', $this->methodName); } diff --git a/src/Definition/ObjectDefinition/PropertyInjection.php b/src/Definition/ObjectDefinition/PropertyInjection.php index 85ebb9882..f9f4ea083 100644 --- a/src/Definition/ObjectDefinition/PropertyInjection.php +++ b/src/Definition/ObjectDefinition/PropertyInjection.php @@ -15,9 +15,8 @@ class PropertyInjection /** * Value that should be injected in the property. - * @var mixed */ - private $value; + private mixed $value; /** * Use for injecting in properties of parent classes: the class name @@ -30,7 +29,7 @@ class PropertyInjection * @param string $propertyName Property name * @param mixed $value Value that should be injected in the property */ - public function __construct(string $propertyName, $value, string $className = null) + public function __construct(string $propertyName, mixed $value, string $className = null) { $this->propertyName = $propertyName; $this->value = $value; @@ -45,7 +44,7 @@ public function getPropertyName() : string /** * @return mixed Value that should be injected in the property */ - public function getValue() + public function getValue(): mixed { return $this->value; } diff --git a/src/Definition/Reference.php b/src/Definition/Reference.php index fe54ed69d..abfedc0d0 100644 --- a/src/Definition/Reference.php +++ b/src/Definition/Reference.php @@ -13,22 +13,15 @@ */ class Reference implements Definition, SelfResolvingDefinition { - /** - * Entry name. - */ + /** Entry name. */ private string $name = ''; - /** - * Name of the target entry. - */ - private string $targetEntryName; - /** * @param string $targetEntryName Name of the target entry */ - public function __construct(string $targetEntryName) - { - $this->targetEntryName = $targetEntryName; + public function __construct( + private string $targetEntryName, + ) { } public function getName() : string @@ -46,7 +39,7 @@ public function getTargetEntryName() : string return $this->targetEntryName; } - public function resolve(ContainerInterface $container) + public function resolve(ContainerInterface $container): mixed { return $container->get($this->getTargetEntryName()); } @@ -61,7 +54,7 @@ public function replaceNestedDefinitions(callable $replacer) : void // no nested definitions } - public function __toString() + public function __toString(): string { return sprintf( 'get(%s)', diff --git a/src/Definition/Resolver/ArrayResolver.php b/src/Definition/Resolver/ArrayResolver.php index 20446474a..7bc641ec9 100644 --- a/src/Definition/Resolver/ArrayResolver.php +++ b/src/Definition/Resolver/ArrayResolver.php @@ -17,14 +17,12 @@ */ class ArrayResolver implements DefinitionResolver { - private DefinitionResolver $definitionResolver; - /** * @param DefinitionResolver $definitionResolver Used to resolve nested definitions. */ - public function __construct(DefinitionResolver $definitionResolver) - { - $this->definitionResolver = $definitionResolver; + public function __construct( + private DefinitionResolver $definitionResolver + ) { } /** @@ -53,7 +51,7 @@ public function isResolvable(Definition $definition, array $parameters = []) : b return true; } - private function resolveDefinition(Definition $value, ArrayDefinition $definition, $key) + private function resolveDefinition(Definition $value, ArrayDefinition $definition, int|string $key): mixed { try { return $this->definitionResolver->resolve($value); diff --git a/src/Definition/Resolver/DecoratorResolver.php b/src/Definition/Resolver/DecoratorResolver.php index 8e54ce6f2..3dc5e8006 100644 --- a/src/Definition/Resolver/DecoratorResolver.php +++ b/src/Definition/Resolver/DecoratorResolver.php @@ -17,20 +17,16 @@ */ class DecoratorResolver implements DefinitionResolver { - private ContainerInterface $container; - - private DefinitionResolver $definitionResolver; - /** * The resolver needs a container. This container will be passed to the factory as a parameter * so that the factory can access other entries of the container. * * @param DefinitionResolver $definitionResolver Used to resolve nested definitions. */ - public function __construct(ContainerInterface $container, DefinitionResolver $definitionResolver) - { - $this->container = $container; - $this->definitionResolver = $definitionResolver; + public function __construct( + private ContainerInterface $container, + private DefinitionResolver $definitionResolver + ) { } /** @@ -40,7 +36,7 @@ public function __construct(ContainerInterface $container, DefinitionResolver $d * * @param DecoratorDefinition $definition */ - public function resolve(Definition $definition, array $parameters = []) + public function resolve(Definition $definition, array $parameters = []): mixed { $callable = $definition->getCallable(); @@ -66,7 +62,7 @@ public function resolve(Definition $definition, array $parameters = []) $decorated = $this->definitionResolver->resolve($decoratedDefinition, $parameters); - return call_user_func($callable, $decorated, $this->container); + return $callable($decorated, $this->container); } public function isResolvable(Definition $definition, array $parameters = []) : bool diff --git a/src/Definition/Resolver/DefinitionResolver.php b/src/Definition/Resolver/DefinitionResolver.php index 56b538346..4a9275647 100644 --- a/src/Definition/Resolver/DefinitionResolver.php +++ b/src/Definition/Resolver/DefinitionResolver.php @@ -25,7 +25,7 @@ interface DefinitionResolver * * @return mixed Value obtained from the definition. */ - public function resolve(Definition $definition, array $parameters = []); + public function resolve(Definition $definition, array $parameters = []): mixed; /** * Check if a definition can be resolved. diff --git a/src/Definition/Resolver/EnvironmentVariableResolver.php b/src/Definition/Resolver/EnvironmentVariableResolver.php index 26ba4737f..0e8bdb72b 100644 --- a/src/Definition/Resolver/EnvironmentVariableResolver.php +++ b/src/Definition/Resolver/EnvironmentVariableResolver.php @@ -15,17 +15,10 @@ */ class EnvironmentVariableResolver implements DefinitionResolver { - private DefinitionResolver $definitionResolver; - - /** - * @var callable - */ - private $variableReader; - - public function __construct(DefinitionResolver $definitionResolver, $variableReader = 'getenv') - { - $this->definitionResolver = $definitionResolver; - $this->variableReader = $variableReader; + public function __construct( + private DefinitionResolver $definitionResolver, + private $variableReader = 'getenv', + ) { } /** @@ -33,7 +26,7 @@ public function __construct(DefinitionResolver $definitionResolver, $variableRea * * @param EnvironmentVariableDefinition $definition */ - public function resolve(Definition $definition, array $parameters = []) + public function resolve(Definition $definition, array $parameters = []): mixed { $value = call_user_func($this->variableReader, $definition->getVariableName()); diff --git a/src/Definition/Resolver/FactoryResolver.php b/src/Definition/Resolver/FactoryResolver.php index 8bd87692f..e6d3f52de 100644 --- a/src/Definition/Resolver/FactoryResolver.php +++ b/src/Definition/Resolver/FactoryResolver.php @@ -25,20 +25,16 @@ */ class FactoryResolver implements DefinitionResolver { - private ContainerInterface $container; - private ?Invoker $invoker = null; - private DefinitionResolver $resolver; - /** * The resolver needs a container. This container will be passed to the factory as a parameter * so that the factory can access other entries of the container. */ - public function __construct(ContainerInterface $container, DefinitionResolver $resolver) - { - $this->container = $container; - $this->resolver = $resolver; + public function __construct( + private ContainerInterface $container, + private DefinitionResolver $resolver, + ) { } /** @@ -48,7 +44,7 @@ public function __construct(ContainerInterface $container, DefinitionResolver $r * * @param FactoryDefinition $definition */ - public function resolve(Definition $definition, array $parameters = []) + public function resolve(Definition $definition, array $parameters = []): mixed { if (! $this->invoker) { $parameterResolver = new ResolverChain([ diff --git a/src/Definition/Resolver/ObjectCreator.php b/src/Definition/Resolver/ObjectCreator.php index cefa7553f..e0470a7a7 100644 --- a/src/Definition/Resolver/ObjectCreator.php +++ b/src/Definition/Resolver/ObjectCreator.php @@ -24,22 +24,16 @@ */ class ObjectCreator implements DefinitionResolver { - private ProxyFactory $proxyFactory; - private ParameterResolver $parameterResolver; - private DefinitionResolver $definitionResolver; - /** * @param DefinitionResolver $definitionResolver Used to resolve nested definitions. * @param ProxyFactory $proxyFactory Used to create proxies for lazy injections. */ public function __construct( - DefinitionResolver $definitionResolver, - ProxyFactory $proxyFactory + private DefinitionResolver $definitionResolver, + private ProxyFactory $proxyFactory ) { - $this->definitionResolver = $definitionResolver; - $this->proxyFactory = $proxyFactory; $this->parameterResolver = new ParameterResolver($definitionResolver); } @@ -115,6 +109,7 @@ private function createInstance(ObjectDefinition $definition, array $parameters) )); } + /** @psalm-var class-string $classname */ $classname = $definition->getClassName(); $classReflection = new ReflectionClass($classname); @@ -147,7 +142,7 @@ private function createInstance(ObjectDefinition $definition, array $parameters) return $object; } - protected function injectMethodsAndProperties($object, ObjectDefinition $objectDefinition) : void + protected function injectMethodsAndProperties(object $object, ObjectDefinition $objectDefinition) : void { // Property injections foreach ($objectDefinition->getPropertyInjections() as $propertyInjection) { @@ -172,7 +167,7 @@ protected function injectMethodsAndProperties($object, ObjectDefinition $objectD * @throws DependencyException * @throws InvalidDefinition */ - private function injectProperty($object, PropertyInjection $propertyInjection) : void + private function injectProperty(object $object, PropertyInjection $propertyInjection) : void { $propertyName = $propertyInjection->getPropertyName(); @@ -196,7 +191,7 @@ private function injectProperty($object, PropertyInjection $propertyInjection) : self::setPrivatePropertyValue($propertyInjection->getClassName(), $object, $propertyName, $value); } - public static function setPrivatePropertyValue(string $className = null, $object, string $propertyName, $propertyValue) : void + public static function setPrivatePropertyValue(?string $className, $object, string $propertyName, mixed $propertyValue) : void { $className = $className ?: get_class($object); diff --git a/src/Definition/Resolver/ParameterResolver.php b/src/Definition/Resolver/ParameterResolver.php index b786b9cf1..bae2cd623 100644 --- a/src/Definition/Resolver/ParameterResolver.php +++ b/src/Definition/Resolver/ParameterResolver.php @@ -18,14 +18,12 @@ */ class ParameterResolver { - private DefinitionResolver $definitionResolver; - /** * @param DefinitionResolver $definitionResolver Will be used to resolve nested definitions. */ - public function __construct(DefinitionResolver $definitionResolver) - { - $this->definitionResolver = $definitionResolver; + public function __construct( + private DefinitionResolver $definitionResolver, + ) { } /** @@ -35,8 +33,8 @@ public function __construct(DefinitionResolver $definitionResolver) public function resolveParameters( MethodInjection $definition = null, ReflectionMethod $method = null, - array $parameters = [] - ) { + array $parameters = [], + ): array { $args = []; if (! $method) { @@ -86,13 +84,12 @@ public function resolveParameters( * Returns the default value of a function parameter. * * @throws InvalidDefinition Can't get default values from PHP internal classes and functions - * @return mixed */ - private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function) + private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function): mixed { try { return $parameter->getDefaultValue(); - } catch (\ReflectionException $e) { + } catch (\ReflectionException) { throw new InvalidDefinition(sprintf( 'The parameter "%s" of %s has no type defined or guessable. It has a default value, ' . 'but the default value can\'t be read through Reflection because it is a PHP internal class.', diff --git a/src/Definition/Resolver/ResolverDispatcher.php b/src/Definition/Resolver/ResolverDispatcher.php index 67f20f832..47b5a16e5 100644 --- a/src/Definition/Resolver/ResolverDispatcher.php +++ b/src/Definition/Resolver/ResolverDispatcher.php @@ -26,10 +26,6 @@ */ class ResolverDispatcher implements DefinitionResolver { - private ContainerInterface $container; - - private ProxyFactory $proxyFactory; - private ?ArrayResolver $arrayResolver = null; private ?FactoryResolver $factoryResolver = null; private ?DecoratorResolver $decoratorResolver = null; @@ -37,10 +33,10 @@ class ResolverDispatcher implements DefinitionResolver private ?InstanceInjector $instanceResolver = null; private ?EnvironmentVariableResolver $envVariableResolver = null; - public function __construct(ContainerInterface $container, ProxyFactory $proxyFactory) - { - $this->container = $container; - $this->proxyFactory = $proxyFactory; + public function __construct( + private ContainerInterface $container, + private ProxyFactory $proxyFactory, + ) { } /** @@ -53,7 +49,7 @@ public function __construct(ContainerInterface $container, ProxyFactory $proxyFa * * @return mixed Value obtained from the definition. */ - public function resolve(Definition $definition, array $parameters = []) + public function resolve(Definition $definition, array $parameters = []): mixed { // Special case, tested early for speed if ($definition instanceof SelfResolvingDefinition) { @@ -122,7 +118,7 @@ private function getDefinitionResolver(Definition $definition) : DefinitionResol return $this->instanceResolver; default: - throw new \RuntimeException('No definition resolver was configured for definition of type ' . get_class($definition)); + throw new \RuntimeException('No definition resolver was configured for definition of type ' . $definition::class); } } } diff --git a/src/Definition/SelfResolvingDefinition.php b/src/Definition/SelfResolvingDefinition.php index 745240389..67dd2dc3e 100644 --- a/src/Definition/SelfResolvingDefinition.php +++ b/src/Definition/SelfResolvingDefinition.php @@ -15,10 +15,8 @@ interface SelfResolvingDefinition { /** * Resolve the definition and return the resulting value. - * - * @return mixed */ - public function resolve(ContainerInterface $container); + public function resolve(ContainerInterface $container): mixed; /** * Check if a definition can be resolved. diff --git a/src/Definition/Source/AnnotationBasedAutowiring.php b/src/Definition/Source/AnnotationBasedAutowiring.php index 4fa9f5fda..09603bdfa 100644 --- a/src/Definition/Source/AnnotationBasedAutowiring.php +++ b/src/Definition/Source/AnnotationBasedAutowiring.php @@ -37,7 +37,7 @@ class AnnotationBasedAutowiring implements DefinitionSource, Autowiring /** * @throws InvalidAnnotation */ - public function autowire(string $name, ObjectDefinition $definition = null) + public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null { $className = $definition ? $definition->getClassName() : $name; @@ -65,7 +65,7 @@ public function autowire(string $name, ObjectDefinition $definition = null) * @throws InvalidAnnotation * @throws InvalidArgumentException The class doesn't exist */ - public function getDefinition(string $name) + public function getDefinition(string $name): ObjectDefinition|null { return $this->autowire($name); } @@ -81,7 +81,7 @@ public function getDefinitions() : array /** * Browse the class properties looking for annotated properties. */ - private function readProperties(ReflectionClass $class, ObjectDefinition $definition) + private function readProperties(ReflectionClass $class, ObjectDefinition $definition): void { foreach ($class->getProperties() as $property) { if ($property->isStatic()) { @@ -105,10 +105,10 @@ private function readProperties(ReflectionClass $class, ObjectDefinition $defini /** * @throws InvalidAnnotation */ - private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, $classname = null) + private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, ?string $classname = null): void { // Look for @Inject annotation - $annotation = $this->getAnnotationReader()->getPropertyAnnotation($property, 'DI\Annotation\Inject'); + $annotation = $this->getAnnotationReader()->getPropertyAnnotation($property, Inject::class); if (!$annotation instanceof Inject) { return; } @@ -145,7 +145,7 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de /** * Browse the object's methods looking for annotated methods. */ - private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition) + private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition): void { // This will look in all the methods, including those of the parent classes foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { @@ -174,7 +174,7 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection { // Look for @Inject annotation try { - $annotation = $this->getAnnotationReader()->getMethodAnnotation($method, 'DI\Annotation\Inject'); + $annotation = $this->getAnnotationReader()->getMethodAnnotation($method, Inject::class); } catch (InvalidAnnotation $e) { throw new InvalidAnnotation(sprintf( '@Inject annotation on %s::%s is malformed. %s', @@ -208,11 +208,9 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection } /** - * @param int $parameterIndex - * * @return string|null Entry name or null if not found. */ - private function getMethodParameter($parameterIndex, ReflectionParameter $parameter, array $annotationParameters) + private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters): string|null { // @Inject has definition for this parameter (by index, or by name) if (isset($annotationParameters[$parameterIndex])) { @@ -229,7 +227,7 @@ private function getMethodParameter($parameterIndex, ReflectionParameter $parame // Look for the property type $parameterType = $parameter->getType(); - if ($parameterType && !$parameterType->isBuiltin() && $parameterType instanceof ReflectionNamedType) { + if ($parameterType && $parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) { return $parameterType->getName(); } @@ -250,12 +248,12 @@ public function getAnnotationReader() : Reader /** * @throws InvalidAnnotation */ - private function readInjectableAnnotation(ReflectionClass $class, ObjectDefinition $definition) + private function readInjectableAnnotation(ReflectionClass $class, ObjectDefinition $definition): void { try { /** @var Injectable|null $annotation */ $annotation = $this->getAnnotationReader() - ->getClassAnnotation($class, 'DI\Annotation\Injectable'); + ->getClassAnnotation($class, Injectable::class); } catch (UnexpectedValueException $e) { throw new InvalidAnnotation(sprintf( 'Error while reading @Injectable on %s: %s', diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php index 5466a2c18..3209da51e 100644 --- a/src/Definition/Source/AttributeBasedAutowiring.php +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -38,7 +38,7 @@ public function __construct() /** * @throws InvalidAnnotation */ - public function autowire(string $name, ObjectDefinition $definition = null) + public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null { $className = $definition ? $definition->getClassName() : $name; @@ -66,7 +66,7 @@ public function autowire(string $name, ObjectDefinition $definition = null) * @throws InvalidAnnotation * @throws InvalidArgumentException The class doesn't exist */ - public function getDefinition(string $name) + public function getDefinition(string $name): ObjectDefinition|null { return $this->autowire($name); } @@ -82,7 +82,7 @@ public function getDefinitions() : array /** * Browse the class properties looking for annotated properties. */ - private function readProperties(ReflectionClass $class, ObjectDefinition $definition) + private function readProperties(ReflectionClass $class, ObjectDefinition $definition): void { foreach ($class->getProperties() as $property) { if ($property->isStatic()) { @@ -106,7 +106,7 @@ private function readProperties(ReflectionClass $class, ObjectDefinition $defini /** * @throws InvalidAnnotation */ - private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, $classname = null) : void + private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, ?string $classname = null): void { // Look for #[Inject] annotation try { @@ -157,7 +157,7 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de /** * Browse the object's methods looking for annotated methods. */ - private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition) + private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition): void { // This will look in all the methods, including those of the parent classes foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { @@ -239,7 +239,7 @@ private function getMethodParameter(int $parameterIndex, ReflectionParameter $pa // Look for the property type $parameterType = $parameter->getType(); - if ($parameterType && !$parameterType->isBuiltin() && $parameterType instanceof ReflectionNamedType) { + if ($parameterType && $parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) { return $parameterType->getName(); } diff --git a/src/Definition/Source/Autowiring.php b/src/Definition/Source/Autowiring.php index ae7682afb..90f9500f1 100644 --- a/src/Definition/Source/Autowiring.php +++ b/src/Definition/Source/Autowiring.php @@ -18,7 +18,6 @@ interface Autowiring * Autowire the given definition. * * @throws InvalidDefinition An invalid definition was found. - * @return ObjectDefinition|null */ - public function autowire(string $name, ObjectDefinition $definition = null); + public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null; } diff --git a/src/Definition/Source/DefinitionArray.php b/src/Definition/Source/DefinitionArray.php index 88f2cacb7..ee5367969 100644 --- a/src/Definition/Source/DefinitionArray.php +++ b/src/Definition/Source/DefinitionArray.php @@ -13,28 +13,19 @@ */ class DefinitionArray implements DefinitionSource, MutableDefinitionSource { - const WILDCARD = '*'; + public const WILDCARD = '*'; /** * Matches anything except "\". */ - const WILDCARD_PATTERN = '([^\\\\]+)'; + private const WILDCARD_PATTERN = '([^\\\\]+)'; - /** - * DI definitions in a PHP array. - * @var array - */ - private $definitions = []; + /** DI definitions in a PHP array. */ + private array $definitions; - /** - * Cache of wildcard definitions. - * @var array|null - */ - private $wildcardDefinitions; + /** Cache of wildcard definitions. */ + private ?array $wildcardDefinitions = null; - /** - * @var DefinitionNormalizer - */ - private $normalizer; + private DefinitionNormalizer $normalizer; public function __construct(array $definitions = [], Autowiring $autowiring = null) { @@ -44,14 +35,13 @@ public function __construct(array $definitions = [], Autowiring $autowiring = nu $this->definitions = $definitions; - $autowiring = $autowiring ?: new NoAutowiring; - $this->normalizer = new DefinitionNormalizer($autowiring); + $this->normalizer = new DefinitionNormalizer($autowiring ?: new NoAutowiring); } /** * @param array $definitions DI definitions in a PHP array indexed by the definition name. */ - public function addDefinitions(array $definitions) + public function addDefinitions(array $definitions): void { if (isset($definitions[0])) { throw new \Exception('The PHP-DI definition is not indexed by an entry name in the definition array'); @@ -65,10 +55,7 @@ public function addDefinitions(array $definitions) $this->wildcardDefinitions = null; } - /** - * {@inheritdoc} - */ - public function addDefinition(Definition $definition) + public function addDefinition(Definition $definition): void { $this->definitions[$definition->getName()] = $definition; @@ -76,7 +63,7 @@ public function addDefinition(Definition $definition) $this->wildcardDefinitions = null; } - public function getDefinition(string $name) + public function getDefinition(string $name): Definition|null { // Look for the definition by name if (array_key_exists($name, $this->definitions)) { @@ -90,7 +77,7 @@ public function getDefinition(string $name) if ($this->wildcardDefinitions === null) { $this->wildcardDefinitions = []; foreach ($this->definitions as $key => $definition) { - if (strpos($key, self::WILDCARD) !== false) { + if (str_contains($key, self::WILDCARD)) { $this->wildcardDefinitions[$key] = $definition; } } @@ -99,7 +86,7 @@ public function getDefinition(string $name) // Look in wildcards definitions foreach ($this->wildcardDefinitions as $key => $definition) { // Turn the pattern into a regex - $key = preg_quote($key); + $key = preg_quote($key, '#'); $key = '#' . str_replace('\\' . self::WILDCARD, self::WILDCARD_PATTERN, $key) . '#'; if (preg_match($key, $name, $matches) === 1) { array_shift($matches); @@ -117,7 +104,7 @@ public function getDefinitions() : array // Return all definitions except wildcard definitions $definitions = []; foreach ($this->definitions as $key => $definition) { - if (strpos($key, self::WILDCARD) === false) { + if (! str_contains($key, self::WILDCARD)) { $definitions[$key] = $definition; } } diff --git a/src/Definition/Source/DefinitionFile.php b/src/Definition/Source/DefinitionFile.php index 0c6caffe4..1e197eee2 100644 --- a/src/Definition/Source/DefinitionFile.php +++ b/src/Definition/Source/DefinitionFile.php @@ -4,6 +4,8 @@ namespace DI\Definition\Source; +use DI\Definition\Definition; + /** * Reads DI definitions from a file returning a PHP array. * @@ -11,29 +13,20 @@ */ class DefinitionFile extends DefinitionArray { - /** - * @var bool - */ - private $initialized = false; - - /** - * File containing definitions, or null if the definitions are given as a PHP array. - * @var string|null - */ - private $file; + private bool $initialized = false; /** * @param string $file File in which the definitions are returned as an array. */ - public function __construct($file, Autowiring $autowiring = null) - { + public function __construct( + private string $file, + Autowiring $autowiring = null, + ) { // Lazy-loading to improve performances - $this->file = $file; - parent::__construct([], $autowiring); } - public function getDefinition(string $name) + public function getDefinition(string $name): Definition|null { $this->initialize(); @@ -50,7 +43,7 @@ public function getDefinitions() : array /** * Lazy-loading of the definitions. */ - private function initialize() + private function initialize(): void { if ($this->initialized === true) { return; diff --git a/src/Definition/Source/DefinitionNormalizer.php b/src/Definition/Source/DefinitionNormalizer.php index 99ea36bfe..b5a2f7ea3 100644 --- a/src/Definition/Source/DefinitionNormalizer.php +++ b/src/Definition/Source/DefinitionNormalizer.php @@ -22,14 +22,9 @@ */ class DefinitionNormalizer { - /** - * @var Autowiring - */ - private $autowiring; - - public function __construct(Autowiring $autowiring) - { - $this->autowiring = $autowiring; + public function __construct( + private Autowiring $autowiring, + ) { } /** @@ -37,13 +32,12 @@ public function __construct(Autowiring $autowiring) * * This is usually a definition declared at the root of a definition array. * - * @param mixed $definition * @param string $name The definition name. * @param string[] $wildcardsReplacements Replacements for wildcard definitions. * * @throws InvalidDefinition */ - public function normalizeRootDefinition($definition, string $name, array $wildcardsReplacements = null) : Definition + public function normalizeRootDefinition(mixed $definition, string $name, array $wildcardsReplacements = null) : Definition { if ($definition instanceof DefinitionHelper) { $definition = $definition->getDefinition($name); @@ -83,12 +77,9 @@ public function normalizeRootDefinition($definition, string $name, array $wildca /** * Normalize a definition that is nested in another one. * - * @param mixed $definition - * @return mixed - * * @throws InvalidDefinition */ - public function normalizeNestedDefinition($definition) + public function normalizeNestedDefinition(mixed $definition): mixed { $name = ''; diff --git a/src/Definition/Source/DefinitionSource.php b/src/Definition/Source/DefinitionSource.php index 5aa95dd4b..39e409317 100644 --- a/src/Definition/Source/DefinitionSource.php +++ b/src/Definition/Source/DefinitionSource.php @@ -18,9 +18,8 @@ interface DefinitionSource * Returns the DI definition for the entry name. * * @throws InvalidDefinition An invalid definition was found. - * @return Definition|null */ - public function getDefinition(string $name); + public function getDefinition(string $name): Definition|null; /** * @return Definition[] Definitions indexed by their name. diff --git a/src/Definition/Source/MutableDefinitionSource.php b/src/Definition/Source/MutableDefinitionSource.php index 04221741f..88733a822 100644 --- a/src/Definition/Source/MutableDefinitionSource.php +++ b/src/Definition/Source/MutableDefinitionSource.php @@ -13,5 +13,5 @@ */ interface MutableDefinitionSource extends DefinitionSource { - public function addDefinition(Definition $definition); + public function addDefinition(Definition $definition): void; } diff --git a/src/Definition/Source/NoAutowiring.php b/src/Definition/Source/NoAutowiring.php index dda3e30c6..d94c1d312 100644 --- a/src/Definition/Source/NoAutowiring.php +++ b/src/Definition/Source/NoAutowiring.php @@ -14,7 +14,7 @@ */ class NoAutowiring implements Autowiring { - public function autowire(string $name, ObjectDefinition $definition = null) + public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null { throw new InvalidDefinition(sprintf( 'Cannot autowire entry "%s" because autowiring is disabled', diff --git a/src/Definition/Source/ReflectionBasedAutowiring.php b/src/Definition/Source/ReflectionBasedAutowiring.php index 0ad4cf71f..f42a8ad55 100644 --- a/src/Definition/Source/ReflectionBasedAutowiring.php +++ b/src/Definition/Source/ReflectionBasedAutowiring.php @@ -16,7 +16,7 @@ */ class ReflectionBasedAutowiring implements DefinitionSource, Autowiring { - public function autowire(string $name, ObjectDefinition $definition = null) + public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null { $className = $definition ? $definition->getClassName() : $name; @@ -37,7 +37,7 @@ public function autowire(string $name, ObjectDefinition $definition = null) return $definition; } - public function getDefinition(string $name) + public function getDefinition(string $name): ObjectDefinition|null { return $this->autowire($name); } @@ -68,14 +68,14 @@ private function getParametersDefinition(\ReflectionFunctionAbstract $constructo // No type continue; } - if ($parameterType->isBuiltin()) { - // Primitive types are not supported - continue; - } if (!$parameterType instanceof ReflectionNamedType) { // Union types are not supported continue; } + if ($parameterType->isBuiltin()) { + // Primitive types are not supported + continue; + } $parameters[$index] = new Reference($parameterType->getName()); } diff --git a/src/Definition/Source/SourceCache.php b/src/Definition/Source/SourceCache.php index 6487c2c0c..fe70b6ba9 100644 --- a/src/Definition/Source/SourceCache.php +++ b/src/Definition/Source/SourceCache.php @@ -13,28 +13,15 @@ */ class SourceCache implements DefinitionSource, MutableDefinitionSource { - /** - * @var string - */ - const CACHE_KEY = 'php-di.definitions.'; - - /** - * @var DefinitionSource - */ - private $cachedSource; + public const CACHE_KEY = 'php-di.definitions.'; - /** - * @var string - */ - private $cacheNamespace; - - public function __construct(DefinitionSource $cachedSource, string $cacheNamespace = '') - { - $this->cachedSource = $cachedSource; - $this->cacheNamespace = $cacheNamespace; + public function __construct( + private DefinitionSource $cachedSource, + private string $cacheNamespace = '', + ) { } - public function getDefinition(string $name) + public function getDefinition(string $name): Definition|null { $definition = apcu_fetch($this->getCacheKey($name)); @@ -70,7 +57,7 @@ public function getCacheKey(string $name) : string return self::CACHE_KEY . $this->cacheNamespace . $name; } - public function addDefinition(Definition $definition) + public function addDefinition(Definition $definition): void { throw new \LogicException('You cannot set a definition at runtime on a container that has caching enabled. Doing so would risk caching the definition for the next execution, where it might be different. You can either put your definitions in a file, remove the cache or ->set() a raw value directly (PHP object, string, int, ...) instead of a PHP-DI definition.'); } diff --git a/src/Definition/Source/SourceChain.php b/src/Definition/Source/SourceChain.php index b82d618bd..4ce2c330c 100644 --- a/src/Definition/Source/SourceChain.php +++ b/src/Definition/Source/SourceChain.php @@ -17,17 +17,9 @@ class SourceChain implements DefinitionSource, MutableDefinitionSource /** * @var DefinitionSource[] */ - private $sources; + private array $sources; - /** - * @var DefinitionSource - */ - private $rootSource; - - /** - * @var MutableDefinitionSource|null - */ - private $mutableSource; + private ?MutableDefinitionSource $mutableSource; /** * @param DefinitionSource[] $sources @@ -36,7 +28,6 @@ public function __construct(array $sources) { // We want a numerically indexed array to ease the traversal later $this->sources = array_values($sources); - $this->rootSource = $this; } /** @@ -45,7 +36,7 @@ public function __construct(array $sources) * @param int $startIndex Use this parameter to start looking from a specific * point in the source chain. */ - public function getDefinition(string $name, int $startIndex = 0) + public function getDefinition(string $name, int $startIndex = 0): Definition|null { $count = count($this->sources); for ($i = $startIndex; $i < $count; ++$i) { @@ -73,14 +64,12 @@ public function getDefinitions() : array } $names = array_keys($names); - $definitions = array_combine($names, array_map(function (string $name) { + return array_combine($names, array_map(function (string $name) { return $this->getDefinition($name); }, $names)); - - return $definitions; } - public function addDefinition(Definition $definition) + public function addDefinition(Definition $definition): void { if (! $this->mutableSource) { throw new \LogicException("The container's definition source has not been initialized correctly"); @@ -101,7 +90,7 @@ private function resolveExtendedDefinition(ExtendsPreviousDefinition $definition } } - public function setMutableDefinitionSource(MutableDefinitionSource $mutableSource) + public function setMutableDefinitionSource(MutableDefinitionSource $mutableSource): void { $this->mutableSource = $mutableSource; diff --git a/src/Definition/StringDefinition.php b/src/Definition/StringDefinition.php index e901338ab..c897f9972 100644 --- a/src/Definition/StringDefinition.php +++ b/src/Definition/StringDefinition.php @@ -16,16 +16,12 @@ */ class StringDefinition implements Definition, SelfResolvingDefinition { - /** - * Entry name. - */ + /** Entry name. */ private string $name = ''; - private string $expression; - - public function __construct(string $expression) - { - $this->expression = $expression; + public function __construct( + private string $expression, + ) { } public function getName() : string @@ -58,7 +54,7 @@ public function replaceNestedDefinitions(callable $replacer) : void // no nested definitions } - public function __toString() + public function __toString(): string { return $this->expression; } diff --git a/src/Definition/ValueDefinition.php b/src/Definition/ValueDefinition.php index 560ece7c6..b2f188039 100644 --- a/src/Definition/ValueDefinition.php +++ b/src/Definition/ValueDefinition.php @@ -18,17 +18,9 @@ class ValueDefinition implements Definition, SelfResolvingDefinition */ private string $name = ''; - /** - * @var mixed - */ - private $value; - - /** - * @param mixed $value - */ - public function __construct($value) - { - $this->value = $value; + public function __construct( + private mixed $value, + ) { } public function getName() : string @@ -41,15 +33,12 @@ public function setName(string $name) : void $this->name = $name; } - /** - * @return mixed - */ - public function getValue() + public function getValue(): mixed { return $this->value; } - public function resolve(ContainerInterface $container) + public function resolve(ContainerInterface $container): mixed { return $this->getValue(); } @@ -64,7 +53,7 @@ public function replaceNestedDefinitions(callable $replacer) : void // no nested definitions } - public function __toString() + public function __toString(): string { return sprintf('Value (%s)', var_export($this->value, true)); } diff --git a/src/FactoryInterface.php b/src/FactoryInterface.php index 322344ebb..88a72fd20 100644 --- a/src/FactoryInterface.php +++ b/src/FactoryInterface.php @@ -25,7 +25,6 @@ interface FactoryInterface * @throws \InvalidArgumentException The name parameter must be of type string. * @throws DependencyException Error while resolving the entry. * @throws NotFoundException No entry or class found for the given name. - * @return mixed */ - public function make(string $name, array $parameters = []); + public function make(string $name, array $parameters = []): mixed; } diff --git a/src/Invoker/DefinitionParameterResolver.php b/src/Invoker/DefinitionParameterResolver.php index cb1582943..d02b78f05 100644 --- a/src/Invoker/DefinitionParameterResolver.php +++ b/src/Invoker/DefinitionParameterResolver.php @@ -18,11 +18,9 @@ */ class DefinitionParameterResolver implements ParameterResolver { - private DefinitionResolver $definitionResolver; - - public function __construct(DefinitionResolver $definitionResolver) - { - $this->definitionResolver = $definitionResolver; + public function __construct( + private DefinitionResolver $definitionResolver + ) { } public function getParameters( diff --git a/src/Invoker/FactoryParameterResolver.php b/src/Invoker/FactoryParameterResolver.php index 2cb6cc089..122df8d16 100644 --- a/src/Invoker/FactoryParameterResolver.php +++ b/src/Invoker/FactoryParameterResolver.php @@ -20,11 +20,9 @@ */ class FactoryParameterResolver implements ParameterResolver { - private ContainerInterface $container; - - public function __construct(ContainerInterface $container) - { - $this->container = $container; + public function __construct( + private ContainerInterface $container + ) { } public function getParameters( diff --git a/src/functions.php b/src/functions.php index f53651f69..43aa9d93b 100644 --- a/src/functions.php +++ b/src/functions.php @@ -16,10 +16,8 @@ if (! function_exists('DI\value')) { /** * Helper for defining a value. - * - * @param mixed $value */ - function value($value) : ValueDefinition + function value(mixed $value) : ValueDefinition { return new ValueDefinition($value); } @@ -55,10 +53,10 @@ function autowire(?string $className = null) : AutowireDefinitionHelper /** * Helper for defining a container entry using a factory function/callable. * - * @param callable $factory The factory is a callable that takes the container as parameter - * and returns the value to register in the container. + * @param callable|array|string $factory The factory is a callable that takes the container as parameter + * and returns the value to register in the container. */ - function factory($factory) : FactoryDefinitionHelper + function factory(callable|array|string $factory) : FactoryDefinitionHelper { return new FactoryDefinitionHelper($factory); } @@ -77,7 +75,7 @@ function factory($factory) : FactoryDefinitionHelper * @param callable $callable The callable takes the decorated object as first parameter and * the container as second. */ - function decorate($callable) : FactoryDefinitionHelper + function decorate(callable|array|string $callable) : FactoryDefinitionHelper { return new FactoryDefinitionHelper($callable, true); } @@ -100,7 +98,7 @@ function get(string $entryName) : Reference * @param string $variableName The name of the environment variable. * @param mixed $defaultValue The default value to be used if the environment variable is not defined. */ - function env(string $variableName, $defaultValue = null) : EnvironmentVariableDefinition + function env(string $variableName, mixed $defaultValue = null) : EnvironmentVariableDefinition { // Only mark as optional if the default value was *explicitly* provided. $isOptional = 2 === func_num_args(); diff --git a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php index bda1c048b..74207ec7c 100644 --- a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php @@ -345,20 +345,6 @@ public function test_autowire_lazy_object(ContainerBuilder $builder) self::assertTrue($object->isProxyInitialized()); } - /** - * @dataProvider provideContainer - * @requires PHP < 8 - */ - public function test_optional_parameter_followed_by_required_parameters(ContainerBuilder $builder) - { - $container = $builder->build(); - - $object = $container->get(OptionalParameterFollowedByRequiredParameter::class); - - self::assertNull($object->first); - self::assertInstanceOf(\stdClass::class, $object->second); - } - /** * @dataProvider provideContainer */ diff --git a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php index ab73e8e35..84d0e74f4 100644 --- a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php +++ b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php @@ -164,18 +164,4 @@ public function test_factory_not_callable(ContainerBuilder $builder) ]); $builder->build()->get('foo'); } - - /** - * @dataProvider provideContainer - * @requires PHP < 8 - */ - public function test_internal_class_default_parameter_value(ContainerBuilder $builder) - { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); - $this->expectExceptionMessage('The parameter "time" of __construct() has no type defined or guessable. It has a default value, but the default value can\'t be read through Reflection because it is a PHP internal class.'); - $builder->addDefinitions([ - \DateTime::class => autowire(), - ]); - $builder->build()->get(\DateTime::class); - } } diff --git a/tests/UnitTest/ContainerBuilderTest.php b/tests/UnitTest/ContainerBuilderTest.php index 5e6024472..fd9ed839d 100644 --- a/tests/UnitTest/ContainerBuilderTest.php +++ b/tests/UnitTest/ContainerBuilderTest.php @@ -176,17 +176,6 @@ public function should_allow_to_add_definitions_in_an_array() $this->assertSame('barbar', $definition->getValue()); } - /** - * @test - */ - public function errors_when_adding_invalid_definitions() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('ContainerBuilder::addDefinitions() parameter must be a string, an array or a DefinitionSource object, integer given'); - $builder = new ContainerBuilder(FakeContainer::class); - $builder->addDefinitions(123); - } - /** * @test */ From 95a1a77bc3c5044664dd075fed916164e4a7cba5 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 27 Feb 2021 19:28:24 +0100 Subject: [PATCH 15/45] Fix psalm warnings --- psalm.xml | 1 + src/CompiledContainer.php | 2 + src/Container.php | 2 +- src/ContainerBuilder.php | 14 +---- .../Helper/CreateDefinitionHelper.php | 6 +- src/Definition/Resolver/InstanceInjector.php | 1 + src/Definition/Resolver/ObjectCreator.php | 1 + src/Definition/StringDefinition.php | 1 + src/Invoker/FactoryParameterResolver.php | 8 +-- src/Proxy/ProxyFactory.php | 59 ++++++++----------- tests/UnitTest/ContainerBuilderTest.php | 2 +- tests/UnitTest/Proxy/ProxyFactoryTest.php | 2 +- 12 files changed, 43 insertions(+), 56 deletions(-) diff --git a/psalm.xml b/psalm.xml index 30258a709..3193d1823 100644 --- a/psalm.xml +++ b/psalm.xml @@ -10,6 +10,7 @@ + diff --git a/src/CompiledContainer.php b/src/CompiledContainer.php index 1fc6d5605..138b37375 100644 --- a/src/CompiledContainer.php +++ b/src/CompiledContainer.php @@ -36,6 +36,7 @@ public function get($id): mixed return $this->resolvedEntries[$id]; } + /** @psalm-suppress UndefinedConstant */ $method = static::METHOD_MAPPING[$id] ?? null; // If it's a compiled entry, then there is a method in this class @@ -74,6 +75,7 @@ public function has($id): bool } // The parent method is overridden to check in our array, it avoids resolving definitions + /** @psalm-suppress UndefinedConstant */ if (isset(static::METHOD_MAPPING[$id])) { return true; } diff --git a/src/Container.php b/src/Container.php index a49a8a305..8a2f609f3 100644 --- a/src/Container.php +++ b/src/Container.php @@ -86,7 +86,7 @@ public function __construct( $this->delegateContainer = $wrapperContainer ?: $this; $this->definitionSource = $definitionSource ?: $this->createDefaultDefinitionSource(); - $this->proxyFactory = $proxyFactory ?: new ProxyFactory(false); + $this->proxyFactory = $proxyFactory ?: new ProxyFactory; $this->definitionResolver = new ResolverDispatcher($this->delegateContainer, $this->proxyFactory); // Auto-register the container diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index e0a305a70..562c5af8d 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -52,12 +52,7 @@ class ContainerBuilder private bool $useAttributes = false; /** - * If true, write the proxies to disk to improve performances. - */ - private bool $writeProxiesToFile = false; - - /** - * Directory where to write the proxies (if $writeProxiesToFile is enabled). + * If set, write the proxies to disk in this directory to improve performances. */ private ?string $proxyDirectory = null; @@ -144,10 +139,7 @@ public function build() $source = new SourceCache($source, $this->sourceCacheNamespace); } - $proxyFactory = new ProxyFactory( - $this->writeProxiesToFile, - $this->proxyDirectory - ); + $proxyFactory = new ProxyFactory($this->proxyDirectory); $this->locked = true; @@ -267,8 +259,6 @@ public function writeProxiesToFile(bool $writeToFile, string $proxyDirectory = n { $this->ensureNotLocked(); - $this->writeProxiesToFile = $writeToFile; - if ($writeToFile && $proxyDirectory === null) { throw new InvalidArgumentException( 'The proxy directory must be specified if you want to write proxies on disk' diff --git a/src/Definition/Helper/CreateDefinitionHelper.php b/src/Definition/Helper/CreateDefinitionHelper.php index c2a4fa861..3959fe72b 100644 --- a/src/Definition/Helper/CreateDefinitionHelper.php +++ b/src/Definition/Helper/CreateDefinitionHelper.php @@ -68,11 +68,11 @@ public function lazy() : self * This method takes a variable number of arguments, example: * ->constructor($param1, $param2, $param3) * - * @param mixed... $parameters Parameters to use for calling the constructor of the class. + * @param mixed[] $parameters Parameters to use for calling the constructor of the class. * * @return $this */ - public function constructor(...$parameters) : self + public function constructor(mixed ...$parameters) : self { $this->constructor = $parameters; @@ -104,7 +104,7 @@ public function property(string $property, mixed $value) : self * Can be used multiple times to declare multiple calls. * * @param string $method Name of the method to call. - * @param mixed... $parameters Parameters to use for calling the method. + * @param mixed[] $parameters Parameters to use for calling the method. * * @return $this */ diff --git a/src/Definition/Resolver/InstanceInjector.php b/src/Definition/Resolver/InstanceInjector.php index 212b75978..4e88741b0 100644 --- a/src/Definition/Resolver/InstanceInjector.php +++ b/src/Definition/Resolver/InstanceInjector.php @@ -24,6 +24,7 @@ class InstanceInjector extends ObjectCreator */ public function resolve(Definition $definition, array $parameters = []) : ?object { + /** @psalm-suppress InvalidCatch */ try { $this->injectMethodsAndProperties($definition->getInstance(), $definition->getObjectDefinition()); } catch (NotFoundExceptionInterface $e) { diff --git a/src/Definition/Resolver/ObjectCreator.php b/src/Definition/Resolver/ObjectCreator.php index e0470a7a7..da5457f0b 100644 --- a/src/Definition/Resolver/ObjectCreator.php +++ b/src/Definition/Resolver/ObjectCreator.php @@ -115,6 +115,7 @@ private function createInstance(ObjectDefinition $definition, array $parameters) $constructorInjection = $definition->getConstructorInjection(); + /** @psalm-suppress InvalidCatch */ try { $args = $this->parameterResolver->resolveParameters( $constructorInjection, diff --git a/src/Definition/StringDefinition.php b/src/Definition/StringDefinition.php index c897f9972..132f7ed47 100644 --- a/src/Definition/StringDefinition.php +++ b/src/Definition/StringDefinition.php @@ -68,6 +68,7 @@ public static function resolveExpression( ContainerInterface $container ) : string { $callback = function (array $matches) use ($entryName, $container) { + /** @psalm-suppress InvalidCatch */ try { return $container->get($matches[1]); } catch (NotFoundExceptionInterface $e) { diff --git a/src/Invoker/FactoryParameterResolver.php b/src/Invoker/FactoryParameterResolver.php index 122df8d16..0f6c9fc5a 100644 --- a/src/Invoker/FactoryParameterResolver.php +++ b/src/Invoker/FactoryParameterResolver.php @@ -43,14 +43,14 @@ public function getParameters( // No type continue; } - if ($parameterType->isBuiltin()) { - // Primitive types are not supported - continue; - } if (!$parameterType instanceof ReflectionNamedType) { // Union types are not supported continue; } + if ($parameterType->isBuiltin()) { + // Primitive types are not supported + continue; + } $parameterClass = $parameterType->getName(); diff --git a/src/Proxy/ProxyFactory.php b/src/Proxy/ProxyFactory.php index 542ae804f..44e28a731 100644 --- a/src/Proxy/ProxyFactory.php +++ b/src/Proxy/ProxyFactory.php @@ -23,73 +23,64 @@ */ class ProxyFactory { - /** - * If true, write the proxies to disk to improve performances. - */ - private bool $writeProxiesToFile; + private ?LazyLoadingValueHolderFactory $proxyManager = null; /** - * Directory where to write the proxies (if $writeProxiesToFile is enabled). + * @param string|null $proxyDirectory If set, write the proxies to disk in this directory to improve performances. */ - private ?string $proxyDirectory; - - private ?LazyLoadingValueHolderFactory $proxyManager = null; - - public function __construct(bool $writeProxiesToFile = false, string $proxyDirectory = null) - { - $this->writeProxiesToFile = $writeProxiesToFile; - $this->proxyDirectory = $proxyDirectory; + public function __construct( + private ?string $proxyDirectory = null, + ) { } /** * Creates a new lazy proxy instance of the given class with * the given initializer. * - * @param string $className name of the class to be proxied + * @param class-string $className name of the class to be proxied * @param \Closure $initializer initializer to be passed to the proxy */ public function createProxy(string $className, \Closure $initializer) : LazyLoadingInterface { - $this->createProxyManager(); + $proxyManager = $this->proxyManager(); - return $this->proxyManager->createProxy($className, $initializer); + return $proxyManager->createProxy($className, $initializer); } /** * Generates and writes the proxy class to file. * - * @param string $className name of the class to be proxied + * @param class-string $className name of the class to be proxied */ public function generateProxyClass(string $className) : void { // If proxy classes a written to file then we pre-generate the class // If they are not written to file then there is no point to do this - if ($this->writeProxiesToFile) { - $this->createProxyManager(); + if ($this->proxyDirectory) { $this->createProxy($className, function () {}); } } - private function createProxyManager() : void + private function proxyManager() : LazyLoadingValueHolderFactory { - if ($this->proxyManager !== null) { - return; - } + if ($this->proxyManager === null) { + if (! class_exists(Configuration::class)) { + throw new \RuntimeException('The ocramius/proxy-manager library is not installed. Lazy injection requires that library to be installed with Composer in order to work. Run "composer require ocramius/proxy-manager:~2.0".'); + } - if (! class_exists(Configuration::class)) { - throw new \RuntimeException('The ocramius/proxy-manager library is not installed. Lazy injection requires that library to be installed with Composer in order to work. Run "composer require ocramius/proxy-manager:~2.0".'); - } + $config = new Configuration(); - $config = new Configuration(); + if ($this->proxyDirectory) { + $config->setProxiesTargetDir($this->proxyDirectory); + $config->setGeneratorStrategy(new FileWriterGeneratorStrategy(new FileLocator($this->proxyDirectory))); + spl_autoload_register($config->getProxyAutoloader()); + } else { + $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); + } - if ($this->writeProxiesToFile) { - $config->setProxiesTargetDir($this->proxyDirectory); - $config->setGeneratorStrategy(new FileWriterGeneratorStrategy(new FileLocator($this->proxyDirectory))); - spl_autoload_register($config->getProxyAutoloader()); - } else { - $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); + $this->proxyManager = new LazyLoadingValueHolderFactory($config); } - $this->proxyManager = new LazyLoadingValueHolderFactory($config); + return $this->proxyManager; } } diff --git a/tests/UnitTest/ContainerBuilderTest.php b/tests/UnitTest/ContainerBuilderTest.php index fd9ed839d..d6c94a4cc 100644 --- a/tests/UnitTest/ContainerBuilderTest.php +++ b/tests/UnitTest/ContainerBuilderTest.php @@ -42,7 +42,7 @@ public function should_configure_for_development_by_default() // Not compiled $this->assertNotInstanceOf(CompiledContainer::class, $container); // Proxies evaluated in memory - $this->assertFalse($getProperty($container->proxyFactory, 'writeProxiesToFile')); + $this->assertNull($getProperty($container->proxyFactory, 'proxyDirectory')); } /** diff --git a/tests/UnitTest/Proxy/ProxyFactoryTest.php b/tests/UnitTest/Proxy/ProxyFactoryTest.php index 3bac19984..a18a3dcd8 100644 --- a/tests/UnitTest/Proxy/ProxyFactoryTest.php +++ b/tests/UnitTest/Proxy/ProxyFactoryTest.php @@ -18,7 +18,7 @@ class ProxyFactoryTest extends TestCase */ public function should_create_lazy_proxies() { - $factory = new ProxyFactory(false); + $factory = new ProxyFactory; $instance = new ClassToProxy(); $initialized = false; From 18b192faa56cefa0fc280fa2b7b17acc3d32f608 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 27 Feb 2021 19:28:33 +0100 Subject: [PATCH 16/45] Require PHP 8 --- composer.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e50746bc8..8c41c87b5 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "phpstan": "phpstan analyse -l 5 -c phpstan.neon src" }, "require": { - "php": ">=7.4.0", + "php": ">=8.0", "psr/container": "^1.0", "php-di/invoker": "^2.0", "opis/closure": "^3.5.5" @@ -36,7 +36,8 @@ "doctrine/annotations": "^1.7", "ocramius/proxy-manager": "^2.3", "friendsofphp/php-cs-fixer": "^2.4", - "phpstan/phpstan": "^0.12" + "phpstan/phpstan": "^0.12", + "vimeo/psalm": "^4.6" }, "provide": { "psr/container-implementation": "^1.0" From 91d2f1a3bb5f7449666f8e591abd3f6e881d1c0c Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 27 Feb 2021 19:40:48 +0100 Subject: [PATCH 17/45] Psalm templates --- src/Definition/Resolver/ArrayResolver.php | 7 +++++++ src/Definition/Resolver/DecoratorResolver.php | 2 ++ src/Definition/Resolver/DefinitionResolver.php | 6 ++++++ src/Definition/Resolver/EnvironmentVariableResolver.php | 2 ++ src/Definition/Resolver/FactoryResolver.php | 2 ++ src/Definition/Resolver/InstanceInjector.php | 4 +++- src/Definition/Resolver/ObjectCreator.php | 7 +++---- 7 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/Definition/Resolver/ArrayResolver.php b/src/Definition/Resolver/ArrayResolver.php index 7bc641ec9..0464a9bf0 100644 --- a/src/Definition/Resolver/ArrayResolver.php +++ b/src/Definition/Resolver/ArrayResolver.php @@ -12,6 +12,8 @@ /** * Resolves an array definition to a value. * + * @template-implements DefinitionResolver + * * @since 5.0 * @author Matthieu Napoli */ @@ -26,6 +28,8 @@ public function __construct( } /** + * @inheritDoc + * * Resolve an array definition to a value. * * An array definition can contain simple values or references to other entries. @@ -51,6 +55,9 @@ public function isResolvable(Definition $definition, array $parameters = []) : b return true; } + /** + * @throws DependencyException + */ private function resolveDefinition(Definition $value, ArrayDefinition $definition, int|string $key): mixed { try { diff --git a/src/Definition/Resolver/DecoratorResolver.php b/src/Definition/Resolver/DecoratorResolver.php index 3dc5e8006..3a75ae7e7 100644 --- a/src/Definition/Resolver/DecoratorResolver.php +++ b/src/Definition/Resolver/DecoratorResolver.php @@ -12,6 +12,8 @@ /** * Resolves a decorator definition to a value. * + * @template-implements DefinitionResolver + * * @since 5.0 * @author Matthieu Napoli */ diff --git a/src/Definition/Resolver/DefinitionResolver.php b/src/Definition/Resolver/DefinitionResolver.php index 4a9275647..9c36ae18c 100644 --- a/src/Definition/Resolver/DefinitionResolver.php +++ b/src/Definition/Resolver/DefinitionResolver.php @@ -6,12 +6,15 @@ use DI\Definition\Definition; use DI\Definition\Exception\InvalidDefinition; +use DI\DependencyException; /** * Resolves a definition to a value. * * @since 4.0 * @author Matthieu Napoli + * + * @template T of Definition */ interface DefinitionResolver { @@ -19,9 +22,11 @@ interface DefinitionResolver * Resolve a definition to a value. * * @param Definition $definition Object that defines how the value should be obtained. + * @psalm-param T $definition * @param array $parameters Optional parameters to use to build the entry. * * @throws InvalidDefinition If the definition cannot be resolved. + * @throws DependencyException * * @return mixed Value obtained from the definition. */ @@ -31,6 +36,7 @@ public function resolve(Definition $definition, array $parameters = []): mixed; * Check if a definition can be resolved. * * @param Definition $definition Object that defines how the value should be obtained. + * @psalm-param T $definition * @param array $parameters Optional parameters to use to build the entry. */ public function isResolvable(Definition $definition, array $parameters = []) : bool; diff --git a/src/Definition/Resolver/EnvironmentVariableResolver.php b/src/Definition/Resolver/EnvironmentVariableResolver.php index 0e8bdb72b..d20f4aec6 100644 --- a/src/Definition/Resolver/EnvironmentVariableResolver.php +++ b/src/Definition/Resolver/EnvironmentVariableResolver.php @@ -11,6 +11,8 @@ /** * Resolves a environment variable definition to a value. * + * @template-implements DefinitionResolver + * * @author James Harris */ class EnvironmentVariableResolver implements DefinitionResolver diff --git a/src/Definition/Resolver/FactoryResolver.php b/src/Definition/Resolver/FactoryResolver.php index e6d3f52de..d8616d4dd 100644 --- a/src/Definition/Resolver/FactoryResolver.php +++ b/src/Definition/Resolver/FactoryResolver.php @@ -20,6 +20,8 @@ /** * Resolves a factory definition to a value. * + * @template-implements DefinitionResolver + * * @since 4.0 * @author Matthieu Napoli */ diff --git a/src/Definition/Resolver/InstanceInjector.php b/src/Definition/Resolver/InstanceInjector.php index 4e88741b0..b9c76d96a 100644 --- a/src/Definition/Resolver/InstanceInjector.php +++ b/src/Definition/Resolver/InstanceInjector.php @@ -12,10 +12,12 @@ /** * Injects dependencies on an existing instance. * + * @template-implements DefinitionResolver + * * @since 5.0 * @author Matthieu Napoli */ -class InstanceInjector extends ObjectCreator +class InstanceInjector extends ObjectCreator implements DefinitionResolver { /** * Injects dependencies on an existing instance. diff --git a/src/Definition/Resolver/ObjectCreator.php b/src/Definition/Resolver/ObjectCreator.php index da5457f0b..13fdac22a 100644 --- a/src/Definition/Resolver/ObjectCreator.php +++ b/src/Definition/Resolver/ObjectCreator.php @@ -19,6 +19,8 @@ /** * Create objects based on an object definition. * + * @template-implements DefinitionResolver + * * @since 4.0 * @author Matthieu Napoli */ @@ -70,7 +72,7 @@ public function isResolvable(Definition $definition, array $parameters = []) : b */ private function createProxy(ObjectDefinition $definition, array $parameters) : LazyLoadingInterface { - $proxy = $this->proxyFactory->createProxy( + return $this->proxyFactory->createProxy( $definition->getClassName(), function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($definition, $parameters) { $wrappedObject = $this->createInstance($definition, $parameters); @@ -79,8 +81,6 @@ function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($defi return true; } ); - - return $proxy; } /** @@ -166,7 +166,6 @@ protected function injectMethodsAndProperties(object $object, ObjectDefinition $ * @param PropertyInjection $propertyInjection Property injection definition * * @throws DependencyException - * @throws InvalidDefinition */ private function injectProperty(object $object, PropertyInjection $propertyInjection) : void { From 20873db63ecb38a538a1c335210b9a2676bee9c6 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 27 Feb 2021 20:14:03 +0100 Subject: [PATCH 18/45] More psalm fixes --- src/CompiledContainer.php | 2 +- src/Compiler/ObjectCreationCompiler.php | 23 +++++++++------ src/Container.php | 11 ++----- src/ContainerBuilder.php | 5 ++++ .../Dumper/ObjectDefinitionDumper.php | 9 ++++++ src/Definition/ObjectDefinition.php | 2 ++ src/Definition/Resolver/InstanceInjector.php | 1 + src/Definition/Resolver/ObjectCreator.php | 5 +++- .../Source/DefinitionNormalizer.php | 1 + src/Definition/Source/DefinitionSource.php | 2 +- src/Definition/Source/SourceChain.php | 29 +++++++------------ 11 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/CompiledContainer.php b/src/CompiledContainer.php index 138b37375..d6ab46f47 100644 --- a/src/CompiledContainer.php +++ b/src/CompiledContainer.php @@ -70,7 +70,7 @@ public function has($id): bool if (! is_string($id)) { throw new \InvalidArgumentException(sprintf( 'The name parameter must be of type string, %s given', - is_object($id) ? get_class($id) : gettype($id) + get_debug_type($id) )); } diff --git a/src/Compiler/ObjectCreationCompiler.php b/src/Compiler/ObjectCreationCompiler.php index 685641fc7..09b981794 100644 --- a/src/Compiler/ObjectCreationCompiler.php +++ b/src/Compiler/ObjectCreationCompiler.php @@ -28,6 +28,8 @@ public function compile(ObjectDefinition $definition) : string { $this->assertClassIsNotAnonymous($definition); $this->assertClassIsInstantiable($definition); + /** @var class-string $className At this point we have checked the class is valid */ + $className = $definition->getClassName(); // Lazy? if ($definition->isLazy()) { @@ -35,7 +37,7 @@ public function compile(ObjectDefinition $definition) : string } try { - $classReflection = new ReflectionClass($definition->getClassName()); + $classReflection = new ReflectionClass($className); $constructorArguments = $this->resolveParameters($definition->getConstructorInjection(), $classReflection->getConstructor()); $dumpedConstructorArguments = array_map(function ($value) { return $this->compiler->compileValue($value); @@ -44,7 +46,7 @@ public function compile(ObjectDefinition $definition) : string $code = []; $code[] = sprintf( '$object = new %s(%s);', - $definition->getClassName(), + $className, implode(', ', $dumpedConstructorArguments) ); @@ -53,8 +55,8 @@ public function compile(ObjectDefinition $definition) : string $value = $propertyInjection->getValue(); $value = $this->compiler->compileValue($value); - $className = $propertyInjection->getClassName() ?: $definition->getClassName(); - $property = new ReflectionProperty($className, $propertyInjection->getPropertyName()); + $propertyClassName = $propertyInjection->getClassName() ?: $className; + $property = new ReflectionProperty($propertyClassName, $propertyInjection->getPropertyName()); if ($property->isPublic()) { $code[] = sprintf('$object->%s = %s;', $propertyInjection->getPropertyName(), $value); } else { @@ -70,7 +72,7 @@ public function compile(ObjectDefinition $definition) : string // Method injections foreach ($definition->getMethodInjections() as $methodInjection) { - $methodReflection = new \ReflectionMethod($definition->getClassName(), $methodInjection->getMethodName()); + $methodReflection = new ReflectionMethod($className, $methodInjection->getMethodName()); $parameters = $this->resolveParameters($methodInjection, $methodReflection); $dumpedParameters = array_map(function ($value) { @@ -132,9 +134,12 @@ private function compileLazyDefinition(ObjectDefinition $definition) : string $subDefinition->setLazy(false); $subDefinition = $this->compiler->compileValue($subDefinition); - $this->compiler->getProxyFactory()->generateProxyClass($definition->getClassName()); + /** @var class-string $className At this point we have checked the class is valid */ + $className = $definition->getClassName(); - return <<compiler->getProxyFactory()->generateProxyClass($className); + + return <<proxyFactory->createProxy( '{$definition->getClassName()}', function (&\$wrappedObject, \$proxy, \$method, \$params, &\$initializer) { @@ -143,7 +148,7 @@ function (&\$wrappedObject, \$proxy, \$method, \$params, &\$initializer) { return true; } ); -PHP; +STR; } /** @@ -155,7 +160,7 @@ private function getParameterDefaultValue(ReflectionParameter $parameter, Reflec { try { return $parameter->getDefaultValue(); - } catch (\ReflectionException $e) { + } catch (\ReflectionException) { throw new InvalidDefinition(sprintf( 'The parameter "%s" of %s has no type defined or guessable. It has a default value, ' . 'but the default value can\'t be read through Reflection because it is a PHP internal class.', diff --git a/src/Container.php b/src/Container.php index 8a2f609f3..cceaacda1 100644 --- a/src/Container.php +++ b/src/Container.php @@ -154,13 +154,6 @@ private function getDefinition(string $name): ?Definition */ public function make(string $name, array $parameters = []): mixed { - if (! is_string($name)) { - throw new InvalidArgumentException(sprintf( - 'The name parameter must be of type string, %s given', - is_object($name) ? get_class($name) : gettype($name) - )); - } - $definition = $this->getDefinition($name); if (! $definition) { // If the entry is already resolved we return it @@ -186,7 +179,7 @@ public function has($id) : bool if (! is_string($id)) { throw new InvalidArgumentException(sprintf( 'The name parameter must be of type string, %s given', - is_object($id) ? get_class($id) : gettype($id) + get_debug_type($id) )); } @@ -331,7 +324,7 @@ private function getEntryType(mixed $entry) : string return sprintf('Value (%s)', $entry === true ? 'true' : 'false'); } - return sprintf('Value (%s)', is_scalar($entry) ? $entry : ucfirst(gettype($entry))); + return sprintf('Value (%s)', is_scalar($entry) ? (string) $entry : ucfirst(gettype($entry))); } /** diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index 562c5af8d..a34280701 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -37,11 +37,13 @@ class ContainerBuilder { /** * Name of the container class, used to create the container. + * @var class-string */ private string $containerClass; /** * Name of the container parent class, used on compiled container. + * @var class-string */ private string $containerParentClass; @@ -87,6 +89,7 @@ public static function buildDevContainer() : Container /** * @param string $containerClass Name of the container class, used to create the container. + * @psalm-param class-string $containerClass */ public function __construct(string $containerClass = Container::class) { @@ -179,6 +182,7 @@ public function build() * @param string $directory Directory in which to put the compiled container. * @param string $containerClass Name of the compiled class. Customize only if necessary. * @param string $containerParentClass Name of the compiled container parent class. Customize only if necessary. + * @psalm-param class-string $containerParentClass */ public function enableCompilation( string $directory, @@ -188,6 +192,7 @@ public function enableCompilation( $this->ensureNotLocked(); $this->compileToDirectory = $directory; + /** @var class-string */ $this->containerClass = $containerClass; $this->containerParentClass = $containerParentClass; diff --git a/src/Definition/Dumper/ObjectDefinitionDumper.php b/src/Definition/Dumper/ObjectDefinitionDumper.php index 8600a5cd5..9c9ab0944 100644 --- a/src/Definition/Dumper/ObjectDefinitionDumper.php +++ b/src/Definition/Dumper/ObjectDefinitionDumper.php @@ -51,6 +51,9 @@ public function dump(ObjectDefinition $definition) : string return sprintf('Object (' . PHP_EOL . '%s' . PHP_EOL . ')', $str); } + /** + * @param class-string $className + */ private function dumpConstructor(string $className, ObjectDefinition $definition) : string { $str = ''; @@ -80,6 +83,9 @@ private function dumpProperties(ObjectDefinition $definition) : string return $str; } + /** + * @param class-string $className + */ private function dumpMethods(string $className, ObjectDefinition $definition) : string { $str = ''; @@ -93,6 +99,9 @@ private function dumpMethods(string $className, ObjectDefinition $definition) : return $str; } + /** + * @param class-string $className + */ private function dumpMethodParameters(string $className, MethodInjection $methodInjection) : string { $methodReflection = new \ReflectionMethod($className, $methodInjection->getMethodName()); diff --git a/src/Definition/ObjectDefinition.php b/src/Definition/ObjectDefinition.php index 458ed50ce..765c5ed9e 100644 --- a/src/Definition/ObjectDefinition.php +++ b/src/Definition/ObjectDefinition.php @@ -236,6 +236,8 @@ private function updateCache() : void return; } + /** @var class-string $className */ + $class = new ReflectionClass($className); $this->isInstantiable = $class->isInstantiable(); } diff --git a/src/Definition/Resolver/InstanceInjector.php b/src/Definition/Resolver/InstanceInjector.php index b9c76d96a..81c3f63da 100644 --- a/src/Definition/Resolver/InstanceInjector.php +++ b/src/Definition/Resolver/InstanceInjector.php @@ -23,6 +23,7 @@ class InstanceInjector extends ObjectCreator implements DefinitionResolver * Injects dependencies on an existing instance. * * @param InstanceDefinition $definition + * @psalm-suppress ImplementedParamTypeMismatch */ public function resolve(Definition $definition, array $parameters = []) : ?object { diff --git a/src/Definition/Resolver/ObjectCreator.php b/src/Definition/Resolver/ObjectCreator.php index 13fdac22a..61c486f10 100644 --- a/src/Definition/Resolver/ObjectCreator.php +++ b/src/Definition/Resolver/ObjectCreator.php @@ -72,8 +72,11 @@ public function isResolvable(Definition $definition, array $parameters = []) : b */ private function createProxy(ObjectDefinition $definition, array $parameters) : LazyLoadingInterface { + /** @var class-string $className */ + $className = $definition->getClassName(); + return $this->proxyFactory->createProxy( - $definition->getClassName(), + $className, function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($definition, $parameters) { $wrappedObject = $this->createInstance($definition, $parameters); $initializer = null; // turning off further lazy initialization diff --git a/src/Definition/Source/DefinitionNormalizer.php b/src/Definition/Source/DefinitionNormalizer.php index b5a2f7ea3..e23de5d16 100644 --- a/src/Definition/Source/DefinitionNormalizer.php +++ b/src/Definition/Source/DefinitionNormalizer.php @@ -56,6 +56,7 @@ public function normalizeRootDefinition(mixed $definition, string $name, array $ } if ($definition instanceof AutowireDefinition) { + /** @var AutowireDefinition $definition */ $definition = $this->autowiring->autowire($name, $definition); } diff --git a/src/Definition/Source/DefinitionSource.php b/src/Definition/Source/DefinitionSource.php index 39e409317..96e985540 100644 --- a/src/Definition/Source/DefinitionSource.php +++ b/src/Definition/Source/DefinitionSource.php @@ -22,7 +22,7 @@ interface DefinitionSource public function getDefinition(string $name): Definition|null; /** - * @return Definition[] Definitions indexed by their name. + * @return array Definitions indexed by their name. */ public function getDefinitions() : array; } diff --git a/src/Definition/Source/SourceChain.php b/src/Definition/Source/SourceChain.php index 4ce2c330c..6bc7080a4 100644 --- a/src/Definition/Source/SourceChain.php +++ b/src/Definition/Source/SourceChain.php @@ -14,20 +14,14 @@ */ class SourceChain implements DefinitionSource, MutableDefinitionSource { - /** - * @var DefinitionSource[] - */ - private array $sources; - private ?MutableDefinitionSource $mutableSource; /** - * @param DefinitionSource[] $sources + * @param list $sources */ - public function __construct(array $sources) - { - // We want a numerically indexed array to ease the traversal later - $this->sources = array_values($sources); + public function __construct( + private array $sources, + ) { } /** @@ -58,15 +52,14 @@ public function getDefinition(string $name, int $startIndex = 0): Definition|nul public function getDefinitions() : array { - $names = []; - foreach ($this->sources as $source) { - $names = array_merge($names, $source->getDefinitions()); - } - $names = array_keys($names); + $allDefinitions = array_merge(...array_map(fn($source) => $source->getDefinitions(), $this->sources)); + + /** @var string[] $allNames */ + $allNames = array_keys($allDefinitions); + + $allValues = array_filter(array_map(fn($name) => $this->getDefinition($name), $allNames)); - return array_combine($names, array_map(function (string $name) { - return $this->getDefinition($name); - }, $names)); + return array_combine($allNames, $allValues); } public function addDefinition(Definition $definition): void From bc862ffbb31d8bcf501e75e6e6a2487254f2b425 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 27 Feb 2021 20:29:33 +0100 Subject: [PATCH 19/45] Replace phpstan with psalm --- .github/workflows/ci.yml | 28 +++++++----------- composer.json | 4 +-- phpstan-baseline.neon | 62 ---------------------------------------- phpstan.neon | 14 --------- psalm.xml | 2 +- 5 files changed, 12 insertions(+), 98 deletions(-) delete mode 100644 phpstan-baseline.neon delete mode 100644 phpstan.neon diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7598e828..004f1890a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,10 +16,10 @@ jobs: timeout-minutes: 15 strategy: matrix: - php: [ '7.4', '8.0' ] + php: [ '8.0' ] dependency-version: [ '' ] include: - - php: '7.4' + - php: '8.0' dependency-version: '--prefer-lowest' steps: - name: Checkout @@ -28,7 +28,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - tools: composer + tools: composer:v2 coverage: none - name: Cache Composer dependencies uses: actions/cache@v2 @@ -37,14 +37,7 @@ jobs: key: php-${{ matrix.php }}-composer-locked-${{ hashFiles('composer.lock') }} restore-keys: php-${{ matrix.php }}-composer-locked- - name: Install PHP dependencies - if: matrix.php != '8.0' run: composer update ${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-progress --no-suggest - - name: 'Install PHP dependencies on PHP 8 (TODO: remove that)' - if: matrix.php == '8.0' - run: | - # Install Composer 2 - composer self-update --snapshot - composer update --ignore-platform-reqs ${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-progress --no-suggest - name: PHPUnit run: vendor/bin/phpunit @@ -57,8 +50,8 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.4 - tools: composer, cs2pr + php-version: 8.0 + tools: composer:v2, cs2pr coverage: none - name: Cache Composer dependencies uses: actions/cache@v2 @@ -71,8 +64,7 @@ jobs: - name: PHP CS Fixer run: vendor/bin/php-cs-fixer fix --dry-run --format=checkstyle | cs2pr - phpstan: - name: PHPStan + psalm: runs-on: ubuntu-latest steps: - name: Checkout @@ -80,8 +72,8 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.4 - tools: composer, cs2pr + php-version: 8.0 + tools: composer:v2, cs2pr coverage: none - name: Cache Composer dependencies uses: actions/cache@v2 @@ -91,5 +83,5 @@ jobs: restore-keys: php-composer-locked- - name: Install PHP dependencies run: composer install --no-interaction --no-progress --no-suggest - - name: PHPStan - run: vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr + - name: Psalm + run: vendor/bin/psalm --output-format=checkstyle | cs2pr diff --git a/composer.json b/composer.json index 8c41c87b5..b0c994fab 100644 --- a/composer.json +++ b/composer.json @@ -21,8 +21,7 @@ }, "scripts": { "test": "phpunit", - "format-code": "php-cs-fixer fix --allow-risky=yes", - "phpstan": "phpstan analyse -l 5 -c phpstan.neon src" + "format-code": "php-cs-fixer fix --allow-risky=yes" }, "require": { "php": ">=8.0", @@ -36,7 +35,6 @@ "doctrine/annotations": "^1.7", "ocramius/proxy-manager": "^2.3", "friendsofphp/php-cs-fixer": "^2.4", - "phpstan/phpstan": "^0.12", "vimeo/psalm": "^4.6" }, "provide": { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon deleted file mode 100644 index aca40e3c7..000000000 --- a/phpstan-baseline.neon +++ /dev/null @@ -1,62 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" - count: 1 - path: src\CompiledContainer.php - - - - message: "#^Negated boolean expression is always false\\.$#" - count: 1 - path: src\CompiledContainer.php - - - - message: "#^Negated boolean expression is always false\\.$#" - count: 2 - path: src\Compiler\Compiler.php - - - - message: "#^If condition is always false\\.$#" - count: 1 - path: src\Compiler\Compiler.php - - - - message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" - count: 2 - path: src\Container.php - - - - message: "#^Negated boolean expression is always false\\.$#" - count: 1 - path: src\Container.php - - - - message: "#^Result of && is always false\\.$#" - count: 1 - path: src\ContainerBuilder.php - - - - message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" - count: 1 - path: src\ContainerBuilder.php - - - - message: "#^Negated boolean expression is always false\\.$#" - count: 1 - path: src\Definition\ArrayDefinitionExtension.php - - - - message: "#^Parameter \\#1 \\$definition \\(DI\\\\Definition\\\\InstanceDefinition\\) of method DI\\\\Definition\\\\Resolver\\\\InstanceInjector\\:\\:resolve\\(\\) should be compatible with parameter \\$definition \\(DI\\\\Definition\\\\ObjectDefinition\\) of method DI\\\\Definition\\\\Resolver\\\\ObjectCreator\\:\\:resolve\\(\\)$#" - count: 1 - path: src\Definition\Resolver\InstanceInjector.php - - - - message: "#^Instanceof between DI\\\\Definition\\\\Definition and DI\\\\Definition\\\\AutowireDefinition will always evaluate to false\\.$#" - count: 1 - path: src\Definition\Source\SourceCache.php - - - - message: "#^Parameter \\#1 \\$autoload_function of function spl_autoload_register expects callable\\(string\\)\\: void, ProxyManager\\\\Autoloader\\\\AutoloaderInterface given\\.$#" - count: 1 - path: src\Proxy\ProxyFactory.php - diff --git a/phpstan.neon b/phpstan.neon deleted file mode 100644 index ec549c629..000000000 --- a/phpstan.neon +++ /dev/null @@ -1,14 +0,0 @@ -includes: - - phpstan-baseline.neon - -parameters: - level: 5 - paths: - - src - excludes_analyse: - - src/Compiler/Template.php - ignoreErrors: - - '#Access to undefined constant DI\\CompiledContainer::METHOD_MAPPING.#' - - '#Function apcu_.* not found.#' - reportUnmatchedIgnoredErrors: false - inferPrivatePropertyTypeFromConstructor: true diff --git a/psalm.xml b/psalm.xml index 3193d1823..92f579ebb 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,6 +1,6 @@ Date: Sat, 27 Feb 2021 20:29:58 +0100 Subject: [PATCH 20/45] Fix code formatting --- src/Annotation/Inject.php | 2 +- src/Annotation/Injectable.php | 2 +- src/Attribute/Inject.php | 6 +++--- src/Attribute/Injectable.php | 2 +- src/CompiledContainer.php | 8 ++++---- src/Compiler/Compiler.php | 2 +- src/Compiler/ObjectCreationCompiler.php | 2 +- src/Compiler/RequestedEntryHolder.php | 2 +- src/Compiler/Template.php | 10 +++++----- src/Container.php | 12 ++++++------ src/ContainerBuilder.php | 2 +- src/Definition/ArrayDefinition.php | 8 ++++---- src/Definition/DecoratorDefinition.php | 2 +- src/Definition/Definition.php | 2 +- src/Definition/Dumper/ObjectDefinitionDumper.php | 12 ++++++------ src/Definition/EnvironmentVariableDefinition.php | 12 ++++++------ src/Definition/Exception/InvalidDefinition.php | 2 +- src/Definition/FactoryDefinition.php | 6 +++--- src/Definition/Helper/AutowireDefinitionHelper.php | 4 ++-- src/Definition/Helper/FactoryDefinitionHelper.php | 2 +- src/Definition/InstanceDefinition.php | 2 +- src/Definition/ObjectDefinition.php | 7 +++---- .../ObjectDefinition/MethodInjection.php | 6 +++--- .../ObjectDefinition/PropertyInjection.php | 2 +- src/Definition/Reference.php | 4 ++-- src/Definition/Resolver/ArrayResolver.php | 4 ++-- src/Definition/Resolver/DecoratorResolver.php | 2 +- src/Definition/Resolver/DefinitionResolver.php | 2 +- .../Resolver/EnvironmentVariableResolver.php | 2 +- src/Definition/Resolver/FactoryResolver.php | 2 +- src/Definition/Resolver/ParameterResolver.php | 4 ++-- src/Definition/Resolver/ResolverDispatcher.php | 2 +- src/Definition/SelfResolvingDefinition.php | 2 +- .../Source/AnnotationBasedAutowiring.php | 14 +++++++------- src/Definition/Source/AttributeBasedAutowiring.php | 11 ++++++----- src/Definition/Source/Autowiring.php | 2 +- src/Definition/Source/DefinitionArray.php | 6 +++--- src/Definition/Source/DefinitionFile.php | 4 ++-- src/Definition/Source/DefinitionNormalizer.php | 2 +- src/Definition/Source/DefinitionSource.php | 2 +- src/Definition/Source/MutableDefinitionSource.php | 2 +- src/Definition/Source/NoAutowiring.php | 2 +- .../Source/ReflectionBasedAutowiring.php | 4 ++-- src/Definition/Source/SourceCache.php | 4 ++-- src/Definition/Source/SourceChain.php | 10 +++++----- src/Definition/StringDefinition.php | 2 +- src/Definition/ValueDefinition.php | 6 +++--- src/FactoryInterface.php | 2 +- src/functions.php | 4 ++-- 49 files changed, 109 insertions(+), 109 deletions(-) diff --git a/src/Annotation/Inject.php b/src/Annotation/Inject.php index cc3f7d550..12021ad3c 100644 --- a/src/Annotation/Inject.php +++ b/src/Annotation/Inject.php @@ -76,7 +76,7 @@ public function __construct(array $values) /** * @return string|null Name of the entry to inject */ - public function getName() : string|null + public function getName() : string | null { return $this->name; } diff --git a/src/Annotation/Injectable.php b/src/Annotation/Injectable.php index ddab369bc..b35436582 100644 --- a/src/Annotation/Injectable.php +++ b/src/Annotation/Injectable.php @@ -31,7 +31,7 @@ public function __construct(array $values) } } - public function isLazy() : bool|null + public function isLazy() : bool | null { return $this->lazy; } diff --git a/src/Attribute/Inject.php b/src/Attribute/Inject.php index 74ca4fd16..299d34e99 100644 --- a/src/Attribute/Inject.php +++ b/src/Attribute/Inject.php @@ -34,7 +34,7 @@ final class Inject /** * @throws InvalidAnnotation */ - public function __construct(string|array|null $name = null) + public function __construct(string | array | null $name = null) { // #[Inject('foo')] or #[Inject(name: 'foo')] if (is_string($name)) { @@ -47,7 +47,7 @@ public function __construct(string|array|null $name = null) if (! is_string($value)) { throw new InvalidAnnotation(sprintf( "#[Inject(['param' => 'value'])] expects \"value\" to be a string, %s given.", - json_encode($value, JSON_THROW_ON_ERROR) + json_encode($value, \JSON_THROW_ON_ERROR) )); } @@ -59,7 +59,7 @@ public function __construct(string|array|null $name = null) /** * @return string|null Name of the entry to inject */ - public function getName() : string|null + public function getName() : string | null { return $this->name; } diff --git a/src/Attribute/Injectable.php b/src/Attribute/Injectable.php index 2acb78326..4bb46bd07 100644 --- a/src/Attribute/Injectable.php +++ b/src/Attribute/Injectable.php @@ -27,7 +27,7 @@ public function __construct( ) { } - public function isLazy() : bool|null + public function isLazy() : bool | null { return $this->lazy; } diff --git a/src/CompiledContainer.php b/src/CompiledContainer.php index d6ab46f47..31f61cc62 100644 --- a/src/CompiledContainer.php +++ b/src/CompiledContainer.php @@ -29,7 +29,7 @@ abstract class CompiledContainer extends Container /** * {@inheritdoc} */ - public function get($id): mixed + public function get($id) : mixed { // Try to find the entry in the singleton map if (isset($this->resolvedEntries[$id]) || array_key_exists($id, $this->resolvedEntries)) { @@ -65,7 +65,7 @@ public function get($id): mixed /** * {@inheritdoc} */ - public function has($id): bool + public function has($id) : bool { if (! is_string($id)) { throw new \InvalidArgumentException(sprintf( @@ -83,7 +83,7 @@ public function has($id): bool return parent::has($id); } - protected function setDefinition(string $name, Definition $definition): void + protected function setDefinition(string $name, Definition $definition) : void { // It needs to be forbidden because that would mean get() must go through the definitions // every time, which kinds of defeats the performance gains of the compiled container @@ -93,7 +93,7 @@ protected function setDefinition(string $name, Definition $definition): void /** * Invoke the given callable. */ - protected function resolveFactory($callable, $entryName, array $extraParameters = []): mixed + protected function resolveFactory($callable, $entryName, array $extraParameters = []) : mixed { // Initialize the factory resolver if (! $this->factoryInvoker) { diff --git a/src/Compiler/Compiler.php b/src/Compiler/Compiler.php index 7cba94022..fa5d4194b 100644 --- a/src/Compiler/Compiler.php +++ b/src/Compiler/Compiler.php @@ -349,7 +349,7 @@ private function createCompilationDirectory(string $directory) : void /** * @return string|true If true is returned that means that the value is compilable. */ - private function isCompilable($value): string|bool + private function isCompilable($value) : string | bool { if ($value instanceof ValueDefinition) { return $this->isCompilable($value->getValue()); diff --git a/src/Compiler/ObjectCreationCompiler.php b/src/Compiler/ObjectCreationCompiler.php index 09b981794..9d165eefa 100644 --- a/src/Compiler/ObjectCreationCompiler.php +++ b/src/Compiler/ObjectCreationCompiler.php @@ -156,7 +156,7 @@ function (&\$wrappedObject, \$proxy, \$method, \$params, &\$initializer) { * * @throws InvalidDefinition Can't get default values from PHP internal classes and functions */ - private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function): mixed + private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function) : mixed { try { return $parameter->getDefaultValue(); diff --git a/src/Compiler/RequestedEntryHolder.php b/src/Compiler/RequestedEntryHolder.php index 04d407505..2d9cba9bb 100644 --- a/src/Compiler/RequestedEntryHolder.php +++ b/src/Compiler/RequestedEntryHolder.php @@ -16,7 +16,7 @@ public function __construct( ) { } - public function getName(): string + public function getName() : string { return $this->name; } diff --git a/src/Compiler/Template.php b/src/Compiler/Template.php index e053639c8..b63b9b815 100644 --- a/src/Compiler/Template.php +++ b/src/Compiler/Template.php @@ -1,16 +1,16 @@ /** * This class has been auto-generated by PHP-DI. */ -class containerClass; ?> extends containerParentClass; ?> +class containerClass; ?> extends containerParentClass; ?> { const METHOD_MAPPING = entryToMethodMapping); ?>; -methods as $methodName => $methodContent) : ?> - protected function () +methods as $methodName => $methodContent) { ?> + protected function () { - + } - + } diff --git a/src/Container.php b/src/Container.php index cceaacda1..c814b3eba 100644 --- a/src/Container.php +++ b/src/Container.php @@ -106,7 +106,7 @@ public function __construct( * @throws DependencyException Error while resolving the entry. * @throws NotFoundException No entry found for the given name. */ - public function get($id): mixed + public function get($id) : mixed { // If the entry is already resolved we return it if (isset($this->resolvedEntries[$id]) || array_key_exists($id, $this->resolvedEntries)) { @@ -125,7 +125,7 @@ public function get($id): mixed return $value; } - private function getDefinition(string $name): ?Definition + private function getDefinition(string $name) : ?Definition { // Local cache that avoids fetching the same definition twice if (!array_key_exists($name, $this->fetchedDefinitions)) { @@ -152,7 +152,7 @@ private function getDefinition(string $name): ?Definition * @throws DependencyException Error while resolving the entry. * @throws NotFoundException No entry found for the given name. */ - public function make(string $name, array $parameters = []): mixed + public function make(string $name, array $parameters = []) : mixed { $definition = $this->getDefinition($name); if (! $definition) { @@ -236,7 +236,7 @@ public function injectOn(object $instance) : object * * @return mixed Result of the function. */ - public function call($callable, array $parameters = []): mixed + public function call($callable, array $parameters = []) : mixed { return $this->getInvoker()->call($callable, $parameters); } @@ -247,7 +247,7 @@ public function call($callable, array $parameters = []): mixed * @param string $name Entry name * @param mixed|DefinitionHelper $value Value, use definition helpers to define objects */ - public function set(string $name, mixed $value): void + public function set(string $name, mixed $value) : void { if ($value instanceof DefinitionHelper) { $value = $value->getDefinition($name); @@ -334,7 +334,7 @@ private function getEntryType(mixed $entry) : string * * @throws DependencyException Error while resolving the entry. */ - private function resolveDefinition(Definition $definition, array $parameters = []): mixed + private function resolveDefinition(Definition $definition, array $parameters = []) : mixed { $entryName = $definition->getName(); diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index a34280701..77cc9e5d3 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -297,7 +297,7 @@ public function wrapContainer(ContainerInterface $otherContainer) : self * or a DefinitionSource object. * @return $this */ - public function addDefinitions(string|array|DefinitionSource ...$definitions) : self + public function addDefinitions(string | array | DefinitionSource ...$definitions) : self { $this->ensureNotLocked(); diff --git a/src/Definition/ArrayDefinition.php b/src/Definition/ArrayDefinition.php index 81c381138..fd0f8b48e 100644 --- a/src/Definition/ArrayDefinition.php +++ b/src/Definition/ArrayDefinition.php @@ -40,9 +40,9 @@ public function replaceNestedDefinitions(callable $replacer) : void $this->values = array_map($replacer, $this->values); } - public function __toString(): string + public function __toString() : string { - $str = '[' . PHP_EOL; + $str = '[' . \PHP_EOL; foreach ($this->values as $key => $value) { if (is_string($key)) { @@ -52,12 +52,12 @@ public function __toString(): string $str .= ' ' . $key . ' => '; if ($value instanceof Definition) { - $str .= str_replace(PHP_EOL, PHP_EOL . ' ', (string) $value); + $str .= str_replace(\PHP_EOL, \PHP_EOL . ' ', (string) $value); } else { $str .= var_export($value, true); } - $str .= ',' . PHP_EOL; + $str .= ',' . \PHP_EOL; } return $str . ']'; diff --git a/src/Definition/DecoratorDefinition.php b/src/Definition/DecoratorDefinition.php index cdbfb72d1..c84ed37d3 100644 --- a/src/Definition/DecoratorDefinition.php +++ b/src/Definition/DecoratorDefinition.php @@ -29,7 +29,7 @@ public function replaceNestedDefinitions(callable $replacer) : void // no nested definitions } - public function __toString(): string + public function __toString() : string { return 'Decorate(' . $this->getName() . ')'; } diff --git a/src/Definition/Definition.php b/src/Definition/Definition.php index ab19087e6..8ceb9c68b 100644 --- a/src/Definition/Definition.php +++ b/src/Definition/Definition.php @@ -33,5 +33,5 @@ public function replaceNestedDefinitions(callable $replacer) : void; /** * Definitions can be cast to string for debugging information. */ - public function __toString(): string; + public function __toString() : string; } diff --git a/src/Definition/Dumper/ObjectDefinitionDumper.php b/src/Definition/Dumper/ObjectDefinitionDumper.php index 9c9ab0944..c59c51000 100644 --- a/src/Definition/Dumper/ObjectDefinitionDumper.php +++ b/src/Definition/Dumper/ObjectDefinitionDumper.php @@ -35,7 +35,7 @@ public function dump(ObjectDefinition $definition) : string $str = sprintf(' class = %s%s', $warning, $className); // Lazy - $str .= PHP_EOL . ' lazy = ' . var_export($definition->isLazy(), true); + $str .= \PHP_EOL . ' lazy = ' . var_export($definition->isLazy(), true); if ($classExist) { // Constructor @@ -48,7 +48,7 @@ public function dump(ObjectDefinition $definition) : string $str .= $this->dumpMethods($className, $definition); } - return sprintf('Object (' . PHP_EOL . '%s' . PHP_EOL . ')', $str); + return sprintf('Object (' . \PHP_EOL . '%s' . \PHP_EOL . ')', $str); } /** @@ -63,7 +63,7 @@ private function dumpConstructor(string $className, ObjectDefinition $definition if ($constructorInjection !== null) { $parameters = $this->dumpMethodParameters($className, $constructorInjection); - $str .= sprintf(PHP_EOL . ' __construct(' . PHP_EOL . ' %s' . PHP_EOL . ' )', $parameters); + $str .= sprintf(\PHP_EOL . ' __construct(' . \PHP_EOL . ' %s' . \PHP_EOL . ' )', $parameters); } return $str; @@ -77,7 +77,7 @@ private function dumpProperties(ObjectDefinition $definition) : string $value = $propertyInjection->getValue(); $valueStr = $value instanceof Definition ? (string) $value : var_export($value, true); - $str .= sprintf(PHP_EOL . ' $%s = %s', $propertyInjection->getPropertyName(), $valueStr); + $str .= sprintf(\PHP_EOL . ' $%s = %s', $propertyInjection->getPropertyName(), $valueStr); } return $str; @@ -93,7 +93,7 @@ private function dumpMethods(string $className, ObjectDefinition $definition) : foreach ($definition->getMethodInjections() as $methodInjection) { $parameters = $this->dumpMethodParameters($className, $methodInjection); - $str .= sprintf(PHP_EOL . ' %s(' . PHP_EOL . ' %s' . PHP_EOL . ' )', $methodInjection->getMethodName(), $parameters); + $str .= sprintf(\PHP_EOL . ' %s(' . \PHP_EOL . ' %s' . \PHP_EOL . ' )', $methodInjection->getMethodName(), $parameters); } return $str; @@ -139,6 +139,6 @@ private function dumpMethodParameters(string $className, MethodInjection $method $args[] = sprintf('$%s = #UNDEFINED#', $parameter->getName()); } - return implode(PHP_EOL . ' ', $args); + return implode(\PHP_EOL . ' ', $args); } } diff --git a/src/Definition/EnvironmentVariableDefinition.php b/src/Definition/EnvironmentVariableDefinition.php index cd17445c5..5b4209675 100644 --- a/src/Definition/EnvironmentVariableDefinition.php +++ b/src/Definition/EnvironmentVariableDefinition.php @@ -56,7 +56,7 @@ public function isOptional() : bool /** * @return mixed The default value to use if the environment variable is optional and not provided */ - public function getDefaultValue(): mixed + public function getDefaultValue() : mixed { return $this->defaultValue; } @@ -66,22 +66,22 @@ public function replaceNestedDefinitions(callable $replacer) : void $this->defaultValue = $replacer($this->defaultValue); } - public function __toString(): string + public function __toString() : string { - $str = ' variable = ' . $this->variableName . PHP_EOL + $str = ' variable = ' . $this->variableName . \PHP_EOL . ' optional = ' . ($this->isOptional ? 'yes' : 'no'); if ($this->isOptional) { if ($this->defaultValue instanceof Definition) { $nestedDefinition = (string) $this->defaultValue; - $defaultValueStr = str_replace(PHP_EOL, PHP_EOL . ' ', $nestedDefinition); + $defaultValueStr = str_replace(\PHP_EOL, \PHP_EOL . ' ', $nestedDefinition); } else { $defaultValueStr = var_export($this->defaultValue, true); } - $str .= PHP_EOL . ' default = ' . $defaultValueStr; + $str .= \PHP_EOL . ' default = ' . $defaultValueStr; } - return sprintf('Environment variable (' . PHP_EOL . '%s' . PHP_EOL . ')', $str); + return sprintf('Environment variable (' . \PHP_EOL . '%s' . \PHP_EOL . ')', $str); } } diff --git a/src/Definition/Exception/InvalidDefinition.php b/src/Definition/Exception/InvalidDefinition.php index 54e602b74..682f1e78c 100644 --- a/src/Definition/Exception/InvalidDefinition.php +++ b/src/Definition/Exception/InvalidDefinition.php @@ -16,7 +16,7 @@ class InvalidDefinition extends \Exception public static function create(Definition $definition, string $message, \Exception $previous = null) : self { return new self(sprintf( - '%s' . PHP_EOL . 'Full definition:' . PHP_EOL . '%s', + '%s' . \PHP_EOL . 'Full definition:' . \PHP_EOL . '%s', $message, (string) $definition ), 0, $previous); diff --git a/src/Definition/FactoryDefinition.php b/src/Definition/FactoryDefinition.php index e027f571f..06a5c3278 100644 --- a/src/Definition/FactoryDefinition.php +++ b/src/Definition/FactoryDefinition.php @@ -33,7 +33,7 @@ class FactoryDefinition implements Definition * @param callable|array|string $factory Callable that returns the value associated to the entry name. * @param array $parameters Parameters to be passed to the callable */ - public function __construct(string $name, callable|array|string $factory, array $parameters = []) + public function __construct(string $name, callable | array | string $factory, array $parameters = []) { $this->name = $name; $this->factory = $factory; @@ -53,7 +53,7 @@ public function setName(string $name) : void /** * @return callable|array|string Callable that returns the value associated to the entry name. */ - public function getCallable(): callable|array|string + public function getCallable() : callable | array | string { return $this->factory; } @@ -71,7 +71,7 @@ public function replaceNestedDefinitions(callable $replacer) : void $this->parameters = array_map($replacer, $this->parameters); } - public function __toString(): string + public function __toString() : string { return 'Factory'; } diff --git a/src/Definition/Helper/AutowireDefinitionHelper.php b/src/Definition/Helper/AutowireDefinitionHelper.php index 7d548672c..fb2086d0d 100644 --- a/src/Definition/Helper/AutowireDefinitionHelper.php +++ b/src/Definition/Helper/AutowireDefinitionHelper.php @@ -28,7 +28,7 @@ class AutowireDefinitionHelper extends CreateDefinitionHelper * * @return $this */ - public function constructorParameter(string|int $parameter, mixed $value) : self + public function constructorParameter(string | int $parameter, mixed $value) : self { $this->constructor[$parameter] = $value; @@ -52,7 +52,7 @@ public function constructorParameter(string|int $parameter, mixed $value) : self * * @return $this */ - public function methodParameter(string $method, string|int $parameter, mixed $value) : self + public function methodParameter(string $method, string | int $parameter, mixed $value) : self { // Special case for the constructor if ($method === '__construct') { diff --git a/src/Definition/Helper/FactoryDefinitionHelper.php b/src/Definition/Helper/FactoryDefinitionHelper.php index a6906c85a..404044538 100644 --- a/src/Definition/Helper/FactoryDefinitionHelper.php +++ b/src/Definition/Helper/FactoryDefinitionHelper.php @@ -26,7 +26,7 @@ class FactoryDefinitionHelper implements DefinitionHelper /** * @param bool $decorate Is the factory decorating a previous definition? */ - public function __construct(callable|array|string $factory, bool $decorate = false) + public function __construct(callable | array | string $factory, bool $decorate = false) { $this->factory = $factory; $this->decorate = $decorate; diff --git a/src/Definition/InstanceDefinition.php b/src/Definition/InstanceDefinition.php index bc1abe535..51bf42e8c 100644 --- a/src/Definition/InstanceDefinition.php +++ b/src/Definition/InstanceDefinition.php @@ -47,7 +47,7 @@ public function replaceNestedDefinitions(callable $replacer) : void $this->objectDefinition->replaceNestedDefinitions($replacer); } - public function __toString(): string + public function __toString() : string { return 'Instance'; } diff --git a/src/Definition/ObjectDefinition.php b/src/Definition/ObjectDefinition.php index 765c5ed9e..a3db27fe6 100644 --- a/src/Definition/ObjectDefinition.php +++ b/src/Definition/ObjectDefinition.php @@ -68,7 +68,7 @@ public function setName(string $name) : void $this->name = $name; } - public function setClassName(?string $className): void + public function setClassName(?string $className) : void { $this->className = $className; @@ -205,7 +205,7 @@ public function replaceNestedDefinitions(callable $replacer) : void * * @param string[] $replacements */ - public function replaceWildcards(array $replacements): void + public function replaceWildcards(array $replacements) : void { $className = $this->getClassName(); @@ -219,7 +219,7 @@ public function replaceWildcards(array $replacements): void $this->setClassName($className); } - public function __toString(): string + public function __toString() : string { return (new ObjectDefinitionDumper)->dump($this); } @@ -237,7 +237,6 @@ private function updateCache() : void } /** @var class-string $className */ - $class = new ReflectionClass($className); $this->isInstantiable = $class->isInstantiable(); } diff --git a/src/Definition/ObjectDefinition/MethodInjection.php b/src/Definition/ObjectDefinition/MethodInjection.php index a6c393c17..f4bfa9afd 100644 --- a/src/Definition/ObjectDefinition/MethodInjection.php +++ b/src/Definition/ObjectDefinition/MethodInjection.php @@ -43,12 +43,12 @@ public function getParameters() : array /** * Replace the parameters of the definition by a new array of parameters. */ - public function replaceParameters(array $parameters): void + public function replaceParameters(array $parameters) : void { $this->parameters = $parameters; } - public function merge(self $definition): void + public function merge(self $definition) : void { // In case of conflicts, the current definition prevails. $this->parameters += $definition->parameters; @@ -72,7 +72,7 @@ public function replaceNestedDefinitions(callable $replacer) : void /** * {@inheritdoc} */ - public function __toString(): string + public function __toString() : string { return sprintf('method(%s)', $this->methodName); } diff --git a/src/Definition/ObjectDefinition/PropertyInjection.php b/src/Definition/ObjectDefinition/PropertyInjection.php index f9f4ea083..9659466b6 100644 --- a/src/Definition/ObjectDefinition/PropertyInjection.php +++ b/src/Definition/ObjectDefinition/PropertyInjection.php @@ -44,7 +44,7 @@ public function getPropertyName() : string /** * @return mixed Value that should be injected in the property */ - public function getValue(): mixed + public function getValue() : mixed { return $this->value; } diff --git a/src/Definition/Reference.php b/src/Definition/Reference.php index abfedc0d0..839e7aa2a 100644 --- a/src/Definition/Reference.php +++ b/src/Definition/Reference.php @@ -39,7 +39,7 @@ public function getTargetEntryName() : string return $this->targetEntryName; } - public function resolve(ContainerInterface $container): mixed + public function resolve(ContainerInterface $container) : mixed { return $container->get($this->getTargetEntryName()); } @@ -54,7 +54,7 @@ public function replaceNestedDefinitions(callable $replacer) : void // no nested definitions } - public function __toString(): string + public function __toString() : string { return sprintf( 'get(%s)', diff --git a/src/Definition/Resolver/ArrayResolver.php b/src/Definition/Resolver/ArrayResolver.php index 0464a9bf0..e02126a7a 100644 --- a/src/Definition/Resolver/ArrayResolver.php +++ b/src/Definition/Resolver/ArrayResolver.php @@ -28,7 +28,7 @@ public function __construct( } /** - * @inheritDoc + * {@inheritDoc} * * Resolve an array definition to a value. * @@ -58,7 +58,7 @@ public function isResolvable(Definition $definition, array $parameters = []) : b /** * @throws DependencyException */ - private function resolveDefinition(Definition $value, ArrayDefinition $definition, int|string $key): mixed + private function resolveDefinition(Definition $value, ArrayDefinition $definition, int | string $key) : mixed { try { return $this->definitionResolver->resolve($value); diff --git a/src/Definition/Resolver/DecoratorResolver.php b/src/Definition/Resolver/DecoratorResolver.php index 3a75ae7e7..a70aa169e 100644 --- a/src/Definition/Resolver/DecoratorResolver.php +++ b/src/Definition/Resolver/DecoratorResolver.php @@ -38,7 +38,7 @@ public function __construct( * * @param DecoratorDefinition $definition */ - public function resolve(Definition $definition, array $parameters = []): mixed + public function resolve(Definition $definition, array $parameters = []) : mixed { $callable = $definition->getCallable(); diff --git a/src/Definition/Resolver/DefinitionResolver.php b/src/Definition/Resolver/DefinitionResolver.php index 9c36ae18c..cb6c2a4b8 100644 --- a/src/Definition/Resolver/DefinitionResolver.php +++ b/src/Definition/Resolver/DefinitionResolver.php @@ -30,7 +30,7 @@ interface DefinitionResolver * * @return mixed Value obtained from the definition. */ - public function resolve(Definition $definition, array $parameters = []): mixed; + public function resolve(Definition $definition, array $parameters = []) : mixed; /** * Check if a definition can be resolved. diff --git a/src/Definition/Resolver/EnvironmentVariableResolver.php b/src/Definition/Resolver/EnvironmentVariableResolver.php index d20f4aec6..d02ab5213 100644 --- a/src/Definition/Resolver/EnvironmentVariableResolver.php +++ b/src/Definition/Resolver/EnvironmentVariableResolver.php @@ -28,7 +28,7 @@ public function __construct( * * @param EnvironmentVariableDefinition $definition */ - public function resolve(Definition $definition, array $parameters = []): mixed + public function resolve(Definition $definition, array $parameters = []) : mixed { $value = call_user_func($this->variableReader, $definition->getVariableName()); diff --git a/src/Definition/Resolver/FactoryResolver.php b/src/Definition/Resolver/FactoryResolver.php index d8616d4dd..d08bc5d8a 100644 --- a/src/Definition/Resolver/FactoryResolver.php +++ b/src/Definition/Resolver/FactoryResolver.php @@ -46,7 +46,7 @@ public function __construct( * * @param FactoryDefinition $definition */ - public function resolve(Definition $definition, array $parameters = []): mixed + public function resolve(Definition $definition, array $parameters = []) : mixed { if (! $this->invoker) { $parameterResolver = new ResolverChain([ diff --git a/src/Definition/Resolver/ParameterResolver.php b/src/Definition/Resolver/ParameterResolver.php index bae2cd623..4c5a1dd5e 100644 --- a/src/Definition/Resolver/ParameterResolver.php +++ b/src/Definition/Resolver/ParameterResolver.php @@ -34,7 +34,7 @@ public function resolveParameters( MethodInjection $definition = null, ReflectionMethod $method = null, array $parameters = [], - ): array { + ) : array { $args = []; if (! $method) { @@ -85,7 +85,7 @@ public function resolveParameters( * * @throws InvalidDefinition Can't get default values from PHP internal classes and functions */ - private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function): mixed + private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function) : mixed { try { return $parameter->getDefaultValue(); diff --git a/src/Definition/Resolver/ResolverDispatcher.php b/src/Definition/Resolver/ResolverDispatcher.php index 47b5a16e5..b26528284 100644 --- a/src/Definition/Resolver/ResolverDispatcher.php +++ b/src/Definition/Resolver/ResolverDispatcher.php @@ -49,7 +49,7 @@ public function __construct( * * @return mixed Value obtained from the definition. */ - public function resolve(Definition $definition, array $parameters = []): mixed + public function resolve(Definition $definition, array $parameters = []) : mixed { // Special case, tested early for speed if ($definition instanceof SelfResolvingDefinition) { diff --git a/src/Definition/SelfResolvingDefinition.php b/src/Definition/SelfResolvingDefinition.php index 67dd2dc3e..be2f274b3 100644 --- a/src/Definition/SelfResolvingDefinition.php +++ b/src/Definition/SelfResolvingDefinition.php @@ -16,7 +16,7 @@ interface SelfResolvingDefinition /** * Resolve the definition and return the resulting value. */ - public function resolve(ContainerInterface $container): mixed; + public function resolve(ContainerInterface $container) : mixed; /** * Check if a definition can be resolved. diff --git a/src/Definition/Source/AnnotationBasedAutowiring.php b/src/Definition/Source/AnnotationBasedAutowiring.php index 09603bdfa..6412df020 100644 --- a/src/Definition/Source/AnnotationBasedAutowiring.php +++ b/src/Definition/Source/AnnotationBasedAutowiring.php @@ -37,7 +37,7 @@ class AnnotationBasedAutowiring implements DefinitionSource, Autowiring /** * @throws InvalidAnnotation */ - public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null { $className = $definition ? $definition->getClassName() : $name; @@ -65,7 +65,7 @@ public function autowire(string $name, ObjectDefinition $definition = null): Obj * @throws InvalidAnnotation * @throws InvalidArgumentException The class doesn't exist */ - public function getDefinition(string $name): ObjectDefinition|null + public function getDefinition(string $name) : ObjectDefinition | null { return $this->autowire($name); } @@ -81,7 +81,7 @@ public function getDefinitions() : array /** * Browse the class properties looking for annotated properties. */ - private function readProperties(ReflectionClass $class, ObjectDefinition $definition): void + private function readProperties(ReflectionClass $class, ObjectDefinition $definition) : void { foreach ($class->getProperties() as $property) { if ($property->isStatic()) { @@ -105,7 +105,7 @@ private function readProperties(ReflectionClass $class, ObjectDefinition $defini /** * @throws InvalidAnnotation */ - private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, ?string $classname = null): void + private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, ?string $classname = null) : void { // Look for @Inject annotation $annotation = $this->getAnnotationReader()->getPropertyAnnotation($property, Inject::class); @@ -145,7 +145,7 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de /** * Browse the object's methods looking for annotated methods. */ - private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition): void + private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition) : void { // This will look in all the methods, including those of the parent classes foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { @@ -210,7 +210,7 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection /** * @return string|null Entry name or null if not found. */ - private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters): string|null + private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters) : string | null { // @Inject has definition for this parameter (by index, or by name) if (isset($annotationParameters[$parameterIndex])) { @@ -248,7 +248,7 @@ public function getAnnotationReader() : Reader /** * @throws InvalidAnnotation */ - private function readInjectableAnnotation(ReflectionClass $class, ObjectDefinition $definition): void + private function readInjectableAnnotation(ReflectionClass $class, ObjectDefinition $definition) : void { try { /** @var Injectable|null $annotation */ diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php index 3209da51e..8e8ef7631 100644 --- a/src/Definition/Source/AttributeBasedAutowiring.php +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -38,7 +38,7 @@ public function __construct() /** * @throws InvalidAnnotation */ - public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null { $className = $definition ? $definition->getClassName() : $name; @@ -66,7 +66,7 @@ public function autowire(string $name, ObjectDefinition $definition = null): Obj * @throws InvalidAnnotation * @throws InvalidArgumentException The class doesn't exist */ - public function getDefinition(string $name): ObjectDefinition|null + public function getDefinition(string $name) : ObjectDefinition | null { return $this->autowire($name); } @@ -82,7 +82,7 @@ public function getDefinitions() : array /** * Browse the class properties looking for annotated properties. */ - private function readProperties(ReflectionClass $class, ObjectDefinition $definition): void + private function readProperties(ReflectionClass $class, ObjectDefinition $definition) : void { foreach ($class->getProperties() as $property) { if ($property->isStatic()) { @@ -106,7 +106,7 @@ private function readProperties(ReflectionClass $class, ObjectDefinition $defini /** * @throws InvalidAnnotation */ - private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, ?string $classname = null): void + private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, ?string $classname = null) : void { // Look for #[Inject] annotation try { @@ -157,7 +157,7 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de /** * Browse the object's methods looking for annotated methods. */ - private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition): void + private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition) : void { // This will look in all the methods, including those of the parent classes foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { @@ -221,6 +221,7 @@ private function getMethodParameter(int $parameterIndex, ReflectionParameter $pa if ($attribute) { /** @var Inject $inject */ $inject = $attribute->newInstance(); + return $inject->getName(); } diff --git a/src/Definition/Source/Autowiring.php b/src/Definition/Source/Autowiring.php index 90f9500f1..0471662e4 100644 --- a/src/Definition/Source/Autowiring.php +++ b/src/Definition/Source/Autowiring.php @@ -19,5 +19,5 @@ interface Autowiring * * @throws InvalidDefinition An invalid definition was found. */ - public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null; + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null; } diff --git a/src/Definition/Source/DefinitionArray.php b/src/Definition/Source/DefinitionArray.php index ee5367969..cf6f880cb 100644 --- a/src/Definition/Source/DefinitionArray.php +++ b/src/Definition/Source/DefinitionArray.php @@ -41,7 +41,7 @@ public function __construct(array $definitions = [], Autowiring $autowiring = nu /** * @param array $definitions DI definitions in a PHP array indexed by the definition name. */ - public function addDefinitions(array $definitions): void + public function addDefinitions(array $definitions) : void { if (isset($definitions[0])) { throw new \Exception('The PHP-DI definition is not indexed by an entry name in the definition array'); @@ -55,7 +55,7 @@ public function addDefinitions(array $definitions): void $this->wildcardDefinitions = null; } - public function addDefinition(Definition $definition): void + public function addDefinition(Definition $definition) : void { $this->definitions[$definition->getName()] = $definition; @@ -63,7 +63,7 @@ public function addDefinition(Definition $definition): void $this->wildcardDefinitions = null; } - public function getDefinition(string $name): Definition|null + public function getDefinition(string $name) : Definition | null { // Look for the definition by name if (array_key_exists($name, $this->definitions)) { diff --git a/src/Definition/Source/DefinitionFile.php b/src/Definition/Source/DefinitionFile.php index 1e197eee2..0f36763e0 100644 --- a/src/Definition/Source/DefinitionFile.php +++ b/src/Definition/Source/DefinitionFile.php @@ -26,7 +26,7 @@ public function __construct( parent::__construct([], $autowiring); } - public function getDefinition(string $name): Definition|null + public function getDefinition(string $name) : Definition | null { $this->initialize(); @@ -43,7 +43,7 @@ public function getDefinitions() : array /** * Lazy-loading of the definitions. */ - private function initialize(): void + private function initialize() : void { if ($this->initialized === true) { return; diff --git a/src/Definition/Source/DefinitionNormalizer.php b/src/Definition/Source/DefinitionNormalizer.php index e23de5d16..d2058410e 100644 --- a/src/Definition/Source/DefinitionNormalizer.php +++ b/src/Definition/Source/DefinitionNormalizer.php @@ -80,7 +80,7 @@ public function normalizeRootDefinition(mixed $definition, string $name, array $ * * @throws InvalidDefinition */ - public function normalizeNestedDefinition(mixed $definition): mixed + public function normalizeNestedDefinition(mixed $definition) : mixed { $name = ''; diff --git a/src/Definition/Source/DefinitionSource.php b/src/Definition/Source/DefinitionSource.php index 96e985540..f12a5f308 100644 --- a/src/Definition/Source/DefinitionSource.php +++ b/src/Definition/Source/DefinitionSource.php @@ -19,7 +19,7 @@ interface DefinitionSource * * @throws InvalidDefinition An invalid definition was found. */ - public function getDefinition(string $name): Definition|null; + public function getDefinition(string $name) : Definition | null; /** * @return array Definitions indexed by their name. diff --git a/src/Definition/Source/MutableDefinitionSource.php b/src/Definition/Source/MutableDefinitionSource.php index 88733a822..28b41d3c5 100644 --- a/src/Definition/Source/MutableDefinitionSource.php +++ b/src/Definition/Source/MutableDefinitionSource.php @@ -13,5 +13,5 @@ */ interface MutableDefinitionSource extends DefinitionSource { - public function addDefinition(Definition $definition): void; + public function addDefinition(Definition $definition) : void; } diff --git a/src/Definition/Source/NoAutowiring.php b/src/Definition/Source/NoAutowiring.php index d94c1d312..067daa629 100644 --- a/src/Definition/Source/NoAutowiring.php +++ b/src/Definition/Source/NoAutowiring.php @@ -14,7 +14,7 @@ */ class NoAutowiring implements Autowiring { - public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null { throw new InvalidDefinition(sprintf( 'Cannot autowire entry "%s" because autowiring is disabled', diff --git a/src/Definition/Source/ReflectionBasedAutowiring.php b/src/Definition/Source/ReflectionBasedAutowiring.php index f42a8ad55..b3f5cc8e1 100644 --- a/src/Definition/Source/ReflectionBasedAutowiring.php +++ b/src/Definition/Source/ReflectionBasedAutowiring.php @@ -16,7 +16,7 @@ */ class ReflectionBasedAutowiring implements DefinitionSource, Autowiring { - public function autowire(string $name, ObjectDefinition $definition = null): ObjectDefinition|null + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null { $className = $definition ? $definition->getClassName() : $name; @@ -37,7 +37,7 @@ public function autowire(string $name, ObjectDefinition $definition = null): Obj return $definition; } - public function getDefinition(string $name): ObjectDefinition|null + public function getDefinition(string $name) : ObjectDefinition | null { return $this->autowire($name); } diff --git a/src/Definition/Source/SourceCache.php b/src/Definition/Source/SourceCache.php index fe70b6ba9..8501f41e0 100644 --- a/src/Definition/Source/SourceCache.php +++ b/src/Definition/Source/SourceCache.php @@ -21,7 +21,7 @@ public function __construct( ) { } - public function getDefinition(string $name): Definition|null + public function getDefinition(string $name) : Definition | null { $definition = apcu_fetch($this->getCacheKey($name)); @@ -57,7 +57,7 @@ public function getCacheKey(string $name) : string return self::CACHE_KEY . $this->cacheNamespace . $name; } - public function addDefinition(Definition $definition): void + public function addDefinition(Definition $definition) : void { throw new \LogicException('You cannot set a definition at runtime on a container that has caching enabled. Doing so would risk caching the definition for the next execution, where it might be different. You can either put your definitions in a file, remove the cache or ->set() a raw value directly (PHP object, string, int, ...) instead of a PHP-DI definition.'); } diff --git a/src/Definition/Source/SourceChain.php b/src/Definition/Source/SourceChain.php index 6bc7080a4..1eec6a1ea 100644 --- a/src/Definition/Source/SourceChain.php +++ b/src/Definition/Source/SourceChain.php @@ -30,7 +30,7 @@ public function __construct( * @param int $startIndex Use this parameter to start looking from a specific * point in the source chain. */ - public function getDefinition(string $name, int $startIndex = 0): Definition|null + public function getDefinition(string $name, int $startIndex = 0) : Definition | null { $count = count($this->sources); for ($i = $startIndex; $i < $count; ++$i) { @@ -52,17 +52,17 @@ public function getDefinition(string $name, int $startIndex = 0): Definition|nul public function getDefinitions() : array { - $allDefinitions = array_merge(...array_map(fn($source) => $source->getDefinitions(), $this->sources)); + $allDefinitions = array_merge(...array_map(fn ($source) => $source->getDefinitions(), $this->sources)); /** @var string[] $allNames */ $allNames = array_keys($allDefinitions); - $allValues = array_filter(array_map(fn($name) => $this->getDefinition($name), $allNames)); + $allValues = array_filter(array_map(fn ($name) => $this->getDefinition($name), $allNames)); return array_combine($allNames, $allValues); } - public function addDefinition(Definition $definition): void + public function addDefinition(Definition $definition) : void { if (! $this->mutableSource) { throw new \LogicException("The container's definition source has not been initialized correctly"); @@ -83,7 +83,7 @@ private function resolveExtendedDefinition(ExtendsPreviousDefinition $definition } } - public function setMutableDefinitionSource(MutableDefinitionSource $mutableSource): void + public function setMutableDefinitionSource(MutableDefinitionSource $mutableSource) : void { $this->mutableSource = $mutableSource; diff --git a/src/Definition/StringDefinition.php b/src/Definition/StringDefinition.php index 132f7ed47..affe70360 100644 --- a/src/Definition/StringDefinition.php +++ b/src/Definition/StringDefinition.php @@ -54,7 +54,7 @@ public function replaceNestedDefinitions(callable $replacer) : void // no nested definitions } - public function __toString(): string + public function __toString() : string { return $this->expression; } diff --git a/src/Definition/ValueDefinition.php b/src/Definition/ValueDefinition.php index b2f188039..7d8f23c16 100644 --- a/src/Definition/ValueDefinition.php +++ b/src/Definition/ValueDefinition.php @@ -33,12 +33,12 @@ public function setName(string $name) : void $this->name = $name; } - public function getValue(): mixed + public function getValue() : mixed { return $this->value; } - public function resolve(ContainerInterface $container): mixed + public function resolve(ContainerInterface $container) : mixed { return $this->getValue(); } @@ -53,7 +53,7 @@ public function replaceNestedDefinitions(callable $replacer) : void // no nested definitions } - public function __toString(): string + public function __toString() : string { return sprintf('Value (%s)', var_export($this->value, true)); } diff --git a/src/FactoryInterface.php b/src/FactoryInterface.php index 88a72fd20..3486b900b 100644 --- a/src/FactoryInterface.php +++ b/src/FactoryInterface.php @@ -26,5 +26,5 @@ interface FactoryInterface * @throws DependencyException Error while resolving the entry. * @throws NotFoundException No entry or class found for the given name. */ - public function make(string $name, array $parameters = []): mixed; + public function make(string $name, array $parameters = []) : mixed; } diff --git a/src/functions.php b/src/functions.php index 43aa9d93b..a6979a6db 100644 --- a/src/functions.php +++ b/src/functions.php @@ -56,7 +56,7 @@ function autowire(?string $className = null) : AutowireDefinitionHelper * @param callable|array|string $factory The factory is a callable that takes the container as parameter * and returns the value to register in the container. */ - function factory(callable|array|string $factory) : FactoryDefinitionHelper + function factory(callable | array | string $factory) : FactoryDefinitionHelper { return new FactoryDefinitionHelper($factory); } @@ -75,7 +75,7 @@ function factory(callable|array|string $factory) : FactoryDefinitionHelper * @param callable $callable The callable takes the decorated object as first parameter and * the container as second. */ - function decorate(callable|array|string $callable) : FactoryDefinitionHelper + function decorate(callable | array | string $callable) : FactoryDefinitionHelper { return new FactoryDefinitionHelper($callable, true); } From da0912c98e7912bf688f34dde0137713c811a0c1 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 6 Mar 2021 21:31:43 +0100 Subject: [PATCH 21/45] Fixes after upping the requirement to PHP 8 --- doc/migration/7.0.md | 2 +- .../IntegrationTest/Definitions/FactoryDefinition/fn.inc | 7 ------- .../IntegrationTest/Definitions/FactoryDefinitionTest.php | 7 +++---- .../Definition/Source/AnnotationBasedAutowiringTest.php | 8 -------- 4 files changed, 4 insertions(+), 20 deletions(-) delete mode 100644 tests/IntegrationTest/Definitions/FactoryDefinition/fn.inc diff --git a/doc/migration/7.0.md b/doc/migration/7.0.md index 0e2d10440..037f23f91 100644 --- a/doc/migration/7.0.md +++ b/doc/migration/7.0.md @@ -11,7 +11,7 @@ This guide will help you migrate from a 6.x version to 7.0. It will only explain ## PHP version -PHP-DI now requires PHP 7.4 or greater. +PHP-DI now requires PHP 8.0 or greater. If you are using an older version, you can of course still use PHP-DI 6. ## PHPdoc types are ignored by `@Inject` diff --git a/tests/IntegrationTest/Definitions/FactoryDefinition/fn.inc b/tests/IntegrationTest/Definitions/FactoryDefinition/fn.inc deleted file mode 100644 index 092600fad..000000000 --- a/tests/IntegrationTest/Definitions/FactoryDefinition/fn.inc +++ /dev/null @@ -1,7 +0,0 @@ - fn () => new stdClass(), -]; diff --git a/tests/IntegrationTest/Definitions/FactoryDefinitionTest.php b/tests/IntegrationTest/Definitions/FactoryDefinitionTest.php index cac73c8dc..21024e5b2 100644 --- a/tests/IntegrationTest/Definitions/FactoryDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/FactoryDefinitionTest.php @@ -614,13 +614,12 @@ public function test_optional_parameters_can_be_omitted(ContainerBuilder $builde self::assertEquals('foo', $container->get('factory')); } - /** - * @requires PHP 7.4 - */ public function test_fn_closures_compilation_is_supported() { $builder = (new ContainerBuilder)->enableCompilation(self::COMPILATION_DIR, self::generateCompiledClassName()); - $builder->addDefinitions(__DIR__ . '/FactoryDefinition/fn.inc'); + $builder->addDefinitions([ + 'factory' => fn () => new stdClass(), + ]); $container = $builder->build(); self::assertEntryIsCompiled($container, 'factory'); diff --git a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php b/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php index 7f56cb1ac..82b27fdbe 100644 --- a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php +++ b/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php @@ -66,10 +66,6 @@ public function testUnguessableProperty() (new AnnotationBasedAutowiring)->autowire(AnnotationFixture4::class); } - /** - * Typed properties support requires PHP 7.4 - * @requires PHP 7.4 - */ public function testTypedProperty() { $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureTypedProperties::class); @@ -79,10 +75,6 @@ public function testTypedProperty() $this->assertHasPropertyInjection($definition, 'typedAndNamed', 'name'); } - /** - * Typed properties support requires PHP 7.4 - * @requires PHP 7.4 - */ public function testScalarTypedPropertiesFail() { $this->expectException(\DI\Definition\Exception\InvalidAnnotation::class); From d84294387410e742c85d561c7b61349a71a4a81b Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 6 Mar 2021 21:34:17 +0100 Subject: [PATCH 22/45] Fix minimum stability --- composer.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/composer.json b/composer.json index b0c994fab..1c9e65eae 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,5 @@ "suggest": { "doctrine/annotations": "Install it if you want to use annotations (version ^1.7)", "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ^2.3)" - }, - "minimum-stability": "dev", - "prefer-stable": true + } } From 9df6976824d08f5007f71bc70c9efdfedfb2d04c Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 6 Mar 2021 21:37:20 +0100 Subject: [PATCH 23/45] Require psr/container 1.1 to strictly type parameters --- composer.json | 2 +- src/Container.php | 17 +++-------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index 1c9e65eae..6db453545 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ }, "require": { "php": ">=8.0", - "psr/container": "^1.0", + "psr/container": "^1.1", "php-di/invoker": "^2.0", "opis/closure": "^3.5.5" }, diff --git a/src/Container.php b/src/Container.php index c814b3eba..7dc11816d 100644 --- a/src/Container.php +++ b/src/Container.php @@ -106,7 +106,7 @@ public function __construct( * @throws DependencyException Error while resolving the entry. * @throws NotFoundException No entry found for the given name. */ - public function get($id) : mixed + public function get(string $id) : mixed { // If the entry is already resolved we return it if (isset($this->resolvedEntries[$id]) || array_key_exists($id, $this->resolvedEntries)) { @@ -168,21 +168,10 @@ public function make(string $name, array $parameters = []) : mixed } /** - * Test if the container can provide something for the given name. - * - * @param string $id Entry name or a class name. - * - * @throws InvalidArgumentException The name parameter must be of type string. + * {@inheritDoc} */ - public function has($id) : bool + public function has(string $id) : bool { - if (! is_string($id)) { - throw new InvalidArgumentException(sprintf( - 'The name parameter must be of type string, %s given', - get_debug_type($id) - )); - } - if (array_key_exists($id, $this->resolvedEntries)) { return true; } From ec8fbdb77d5d44917fcd9be82bc8062cfe8de0fe Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 6 Mar 2021 21:44:03 +0100 Subject: [PATCH 24/45] Remove now useless test --- tests/IntegrationTest/ContainerHasTest.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/IntegrationTest/ContainerHasTest.php b/tests/IntegrationTest/ContainerHasTest.php index cb2f7b423..fca951c0d 100644 --- a/tests/IntegrationTest/ContainerHasTest.php +++ b/tests/IntegrationTest/ContainerHasTest.php @@ -42,15 +42,4 @@ public function test_has_not(ContainerBuilder $builder) { self::assertFalse($builder->build()->has('wow')); } - - /** - * @test - * @dataProvider provideContainer - */ - public function fails_with_non_string_parameter(ContainerBuilder $builder) - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('The name parameter must be of type string'); - $builder->build()->has(new stdClass); - } } From 429164722ce5b5e3f07188b2c1be96c4bb26a336 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 6 Mar 2021 21:44:10 +0100 Subject: [PATCH 25/45] Run APCu tests in CI --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 004f1890a..fc01614f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,7 @@ jobs: php-version: ${{ matrix.php }} tools: composer:v2 coverage: none + extensions: apcu - name: Cache Composer dependencies uses: actions/cache@v2 with: From 902cc91e3b3d7ca915fe275a6f467f8925eeaa0d Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 6 Mar 2021 21:45:27 +0100 Subject: [PATCH 26/45] Support psr/container 2.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6db453545..7e59ffe66 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ }, "require": { "php": ">=8.0", - "psr/container": "^1.1", + "psr/container": "^1.1 || ^2.0", "php-di/invoker": "^2.0", "opis/closure": "^3.5.5" }, From efa8ccdef7e37dc1979318fe9396e242645b4311 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 6 Mar 2021 21:48:44 +0100 Subject: [PATCH 27/45] Run APCu tests in CI --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc01614f5..7349bee70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,9 @@ jobs: php-version: ${{ matrix.php }} tools: composer:v2 coverage: none + # Enable apcu extensions: apcu + ini-values: apc.enable_cli=1 - name: Cache Composer dependencies uses: actions/cache@v2 with: From 957f926e1da6939dbef3eab64dbc499cda529e45 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Fri, 2 Apr 2021 20:38:52 +0200 Subject: [PATCH 28/45] Allow to create the container with definitions --- src/Container.php | 26 ++++++++++++++++++++------ tests/UnitTest/ContainerTest.php | 11 +++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/Container.php b/src/Container.php index 7dc11816d..7dabfbf94 100644 --- a/src/Container.php +++ b/src/Container.php @@ -68,6 +68,15 @@ class Container implements ContainerInterface, FactoryInterface, InvokerInterfac protected ProxyFactory $proxyFactory; + public static function create( + array $definitions + ): static { + $source = new SourceChain([new ReflectionBasedAutowiring]); + $source->setMutableDefinitionSource(new DefinitionArray($definitions, new ReflectionBasedAutowiring)); + + return new static($definitions); + } + /** * Use `$container = new Container()` if you want a container with the default configuration. * @@ -79,13 +88,17 @@ class Container implements ContainerInterface, FactoryInterface, InvokerInterfac * @param ContainerInterface $wrapperContainer If the container is wrapped by another container. */ public function __construct( - MutableDefinitionSource $definitionSource = null, + array|MutableDefinitionSource $definitions = [], ProxyFactory $proxyFactory = null, ContainerInterface $wrapperContainer = null ) { - $this->delegateContainer = $wrapperContainer ?: $this; + if (is_array($definitions)) { + $this->definitionSource = $this->createDefaultDefinitionSource($definitions); + } else { + $this->definitionSource = $definitions; + } - $this->definitionSource = $definitionSource ?: $this->createDefaultDefinitionSource(); + $this->delegateContainer = $wrapperContainer ?: $this; $this->proxyFactory = $proxyFactory ?: new ProxyFactory; $this->definitionResolver = new ResolverDispatcher($this->delegateContainer, $this->proxyFactory); @@ -371,10 +384,11 @@ private function getInvoker() : InvokerInterface return $this->invoker; } - private function createDefaultDefinitionSource() : SourceChain + private function createDefaultDefinitionSource(array $definitions) : SourceChain { - $source = new SourceChain([new ReflectionBasedAutowiring]); - $source->setMutableDefinitionSource(new DefinitionArray([], new ReflectionBasedAutowiring)); + $autowiring = new ReflectionBasedAutowiring; + $source = new SourceChain([$autowiring]); + $source->setMutableDefinitionSource(new DefinitionArray($definitions, $autowiring)); return $source; } diff --git a/tests/UnitTest/ContainerTest.php b/tests/UnitTest/ContainerTest.php index 0ba1b845b..76b0789ce 100644 --- a/tests/UnitTest/ContainerTest.php +++ b/tests/UnitTest/ContainerTest.php @@ -19,4 +19,15 @@ public function canBeBuiltWithoutParameters() { self::assertInstanceOf(Container::class, new Container); // Should not be an error } + /** + * @test + */ + public function canBeBuiltWithDefinitionArray() + { + $container = new Container([ + 'foo' => 'bar', + ]); + self::assertInstanceOf(Container::class, $container); + self::assertEquals('bar', $container->get('foo')); + } } From afb1ca748a99c362fd3feb37f080286bff8b0929 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Fri, 2 Apr 2021 20:42:21 +0200 Subject: [PATCH 29/45] Remove obsolete ContainerBuilder::buildDevContainer() Use `new Container()` instead. --- doc/README.md | 1 + doc/migration/7.0.md | 20 +++++++++++++++++++ src/ContainerBuilder.php | 8 -------- .../IntegrationTest/DelegateContainerTest.php | 13 +++++++----- tests/UnitTest/ContainerBuilderTest.php | 8 -------- tests/UnitTest/ContainerGetTest.php | 13 ++++++------ website/home_modules.twig | 2 +- 7 files changed, 37 insertions(+), 28 deletions(-) diff --git a/doc/README.md b/doc/README.md index 60d6dbf8c..44abbdc75 100644 --- a/doc/README.md +++ b/doc/README.md @@ -45,6 +45,7 @@ title: Documentation index * [Migration from PHP-DI 3.x to 4.0](migration/4.0.md) * [Migration from PHP-DI 4.x to 5.0](migration/5.0.md) * [Migration from PHP-DI 5.x to 6.0](migration/6.0.md) +* [Migration from PHP-DI 6.x to 7.0](migration/7.0.md) ### Internals diff --git a/doc/migration/7.0.md b/doc/migration/7.0.md index 037f23f91..59d6cc64d 100644 --- a/doc/migration/7.0.md +++ b/doc/migration/7.0.md @@ -13,6 +13,26 @@ This guide will help you migrate from a 6.x version to 7.0. It will only explain PHP-DI now requires PHP 8.0 or greater. If you are using an older version, you can of course still use PHP-DI 6. +## Container creation + +The container can now be created with sane defaults without using the `ContainerBuilder` class: + +```php +$container = new \DI\Container(); + +// With definitions: +$container = new \DI\Container([ + \Psr\Log\LoggerInterface::class => get(MyLogger::class), +]); +``` + +Related to that: `\DI\ContainerBuilder::buildDevContainer()` method is now obsolete and has been removed. Replace it with: + +```diff +- $container = \DI\ContainerBuilder::buildDevContainer(); ++ $container = new \DI\Container(); +``` + ## PHPdoc types are ignored by `@Inject` Now that PHP 7.4 and up supports typed properties, PHP-DI will stop reading types from phpdoc. diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index 77cc9e5d3..9ac2d8d0e 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -79,14 +79,6 @@ class ContainerBuilder protected string $sourceCacheNamespace = ''; - /** - * Build a container configured for the dev environment. - */ - public static function buildDevContainer() : Container - { - return new Container; - } - /** * @param string $containerClass Name of the container class, used to create the container. * @psalm-param class-string $containerClass diff --git a/tests/IntegrationTest/DelegateContainerTest.php b/tests/IntegrationTest/DelegateContainerTest.php index 339824862..941fc60bd 100644 --- a/tests/IntegrationTest/DelegateContainerTest.php +++ b/tests/IntegrationTest/DelegateContainerTest.php @@ -4,6 +4,7 @@ namespace DI\Test\IntegrationTest; +use DI\Container; use DI\ContainerBuilder; use function DI\get; use function DI\string; @@ -18,7 +19,7 @@ class DelegateContainerTest extends BaseContainerTest */ public function test_alias_to_dependency_in_delegate_container(ContainerBuilder $subContainerBuilder) { - $rootContainer = ContainerBuilder::buildDevContainer(); + $rootContainer = new Container; $value = new \stdClass(); $rootContainer->set('bar', $value); @@ -36,8 +37,9 @@ public function test_alias_to_dependency_in_delegate_container(ContainerBuilder */ public function test_string_expression_using_dependency_in_delegate_container(ContainerBuilder $subContainerBuilder) { - $rootContainer = ContainerBuilder::buildDevContainer(); - $rootContainer->set('bar', 'hello'); + $rootContainer = new Container([ + 'bar' => 'hello', + ]); $subContainerBuilder->wrapContainer($rootContainer); $subContainerBuilder->addDefinitions([ @@ -53,9 +55,10 @@ public function test_string_expression_using_dependency_in_delegate_container(Co */ public function test_with_container_call(ContainerBuilder $subContainerBuilder) { - $rootContainer = ContainerBuilder::buildDevContainer(); $value = new \stdClass(); - $rootContainer->set('stdClass', $value); + $rootContainer = new Container([ + 'stdClass' => $value, + ]); $subContainerBuilder->wrapContainer($rootContainer); $subContainer = $subContainerBuilder->build(); diff --git a/tests/UnitTest/ContainerBuilderTest.php b/tests/UnitTest/ContainerBuilderTest.php index d6c94a4cc..40011174a 100644 --- a/tests/UnitTest/ContainerBuilderTest.php +++ b/tests/UnitTest/ContainerBuilderTest.php @@ -249,12 +249,4 @@ public function should_throw_if_modified_after_building_a_container() $builder->addDefinitions([]); } - - /** - * @test - */ - public function dev_container_configuration_should_be_identical_to_creating_a_new_container_from_defaults() - { - self::assertEquals(new Container, ContainerBuilder::buildDevContainer()); - } } diff --git a/tests/UnitTest/ContainerGetTest.php b/tests/UnitTest/ContainerGetTest.php index 9ac27e090..f855855ca 100644 --- a/tests/UnitTest/ContainerGetTest.php +++ b/tests/UnitTest/ContainerGetTest.php @@ -4,6 +4,7 @@ namespace DI\Test\UnitTest; +use DI\Container; use DI\ContainerBuilder; use DI\Test\UnitTest\Fixtures\PassByReferenceDependency; use PHPUnit\Framework\TestCase; @@ -18,7 +19,7 @@ class ContainerGetTest extends TestCase { public function testSetGet() { - $container = ContainerBuilder::buildDevContainer(); + $container = new Container; $dummy = new stdClass(); $container->set('key', $dummy); $this->assertSame($dummy, $container->get('key')); @@ -27,7 +28,7 @@ public function testSetGet() public function testGetNotFound() { $this->expectException('DI\NotFoundException'); - $container = ContainerBuilder::buildDevContainer(); + $container = new Container; $container->get('key'); } @@ -36,20 +37,20 @@ public function testClosureIsResolved() $closure = function () { return 'hello'; }; - $container = ContainerBuilder::buildDevContainer(); + $container = new Container; $container->set('key', $closure); $this->assertEquals('hello', $container->get('key')); } public function testGetWithClassName() { - $container = ContainerBuilder::buildDevContainer(); + $container = new Container; $this->assertInstanceOf('stdClass', $container->get('stdClass')); } public function testGetResolvesEntryOnce() { - $container = ContainerBuilder::buildDevContainer(); + $container = new Container; $this->assertSame($container->get('stdClass'), $container->get('stdClass')); } @@ -58,7 +59,7 @@ public function testGetResolvesEntryOnce() */ public function testPassByReferenceParameter() { - $container = ContainerBuilder::buildDevContainer(); + $container = new Container; $object = $container->get(PassByReferenceDependency::class); $this->assertInstanceOf(PassByReferenceDependency::class, $object); } diff --git a/website/home_modules.twig b/website/home_modules.twig index 3780a93d2..60118386e 100644 --- a/website/home_modules.twig +++ b/website/home_modules.twig @@ -12,7 +12,7 @@ Just create the container and you are good to go thanks to autowiring.

-
$container = ContainerBuilder::buildDevContainer();
+
$container = new Container();
 
 $home = $container->get(HomeController::class);
 
From 99b0104f16a28ee8807d41329dda307d66149290 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Fri, 2 Apr 2021 20:53:08 +0200 Subject: [PATCH 30/45] Improve the "Getting started" documentation --- doc/container-configuration.md | 14 +++++++++++--- doc/getting-started.md | 2 +- doc/php-definitions.md | 7 +++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/doc/container-configuration.md b/doc/container-configuration.md index f8a5ebced..5d0311eca 100644 --- a/doc/container-configuration.md +++ b/doc/container-configuration.md @@ -5,15 +5,23 @@ current_menu: container-configuration # Configuring the container -## Development environment +## Getting started -PHP-DI's container is preconfigured for "plug and play", i.e. development environment. You can start using it simply like so: +PHP-DI's container is preconfigured for "plug and play". You can start using it simply like so: ```php $container = new Container(); ``` -By default, PHP-DI will have [Autowiring](definition.md) enabled ([annotations](annotations.md) are disabled by default). +By default, [Autowiring](definition.md) will be enabled. [Annotations](annotations.md) are disabled by default. + +To register [definitions using an array](php-definitions.md): + +```php +$container = new DI\Container([ + // place your definitions here +]); +``` To change options on the container you can use the `ContainerBuilder` class: diff --git a/doc/getting-started.md b/doc/getting-started.md index 2c822cdbd..aa069f924 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -18,7 +18,7 @@ Install PHP-DI with [Composer](http://getcomposer.org/doc/00-intro.md): composer require php-di/php-di ``` -PHP-DI requires PHP 7.2 or above. +PHP-DI 7 requires PHP 8.0 or above. ## Basic usage diff --git a/doc/php-definitions.md b/doc/php-definitions.md index 2ec2edf50..e27563358 100644 --- a/doc/php-definitions.md +++ b/doc/php-definitions.md @@ -10,9 +10,16 @@ On top of [autowiring](autowiring.md) and [annotations](annotations.md), you can You can register that configuration as an array: ```php +$container = new DI\Container([ + // place your definitions here +]); + +// or using the container builder class: +// ... $containerBuilder->addDefinitions([ // place your definitions here ]); +// ... ``` Or by putting it into a file returning an array: From 50819b581888b1cc7f28192ed02e5d9357bbfc03 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Fri, 2 Apr 2021 22:53:08 +0200 Subject: [PATCH 31/45] Fix CS --- src/Container.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Container.php b/src/Container.php index 7dabfbf94..59defab54 100644 --- a/src/Container.php +++ b/src/Container.php @@ -70,7 +70,7 @@ class Container implements ContainerInterface, FactoryInterface, InvokerInterfac public static function create( array $definitions - ): static { + ) : static { $source = new SourceChain([new ReflectionBasedAutowiring]); $source->setMutableDefinitionSource(new DefinitionArray($definitions, new ReflectionBasedAutowiring)); @@ -88,7 +88,7 @@ public static function create( * @param ContainerInterface $wrapperContainer If the container is wrapped by another container. */ public function __construct( - array|MutableDefinitionSource $definitions = [], + array | MutableDefinitionSource $definitions = [], ProxyFactory $proxyFactory = null, ContainerInterface $wrapperContainer = null ) { From d01fdf94ba00ff037a6c2d219fe8a0c5c8d88213 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 9 Apr 2022 18:57:31 +0200 Subject: [PATCH 32/45] Simplify method --- src/Definition/Resolver/EnvironmentVariableResolver.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Definition/Resolver/EnvironmentVariableResolver.php b/src/Definition/Resolver/EnvironmentVariableResolver.php index 6e48af7e7..af992527d 100644 --- a/src/Definition/Resolver/EnvironmentVariableResolver.php +++ b/src/Definition/Resolver/EnvironmentVariableResolver.php @@ -64,12 +64,6 @@ public function isResolvable(Definition $definition, array $parameters = []) : b protected function getEnvVariable(string $variableName) { - if (isset($_ENV[$variableName])) { - return $_ENV[$variableName]; - } elseif (isset($_SERVER[$variableName])) { - return $_SERVER[$variableName]; - } - - return getenv($variableName); + return $_ENV[$variableName] ?? $_SERVER[$variableName] ?? getenv($variableName); } } From aa0ea10a1185087cd9c1ea744a5842675ab85c0c Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 9 Apr 2022 19:31:45 +0200 Subject: [PATCH 33/45] Various code fixes and improvements (PHPStorm warnings) --- src/Compiler/Compiler.php | 14 +++------- src/Definition/ObjectDefinition.php | 4 +-- .../Source/AnnotationBasedAutowiring.php | 2 +- .../Source/AttributeBasedAutowiring.php | 2 +- src/Definition/Source/DefinitionArray.php | 6 ++--- src/Definition/Source/DefinitionFile.php | 2 +- src/Definition/StringDefinition.php | 2 +- src/Proxy/ProxyFactory.php | 6 ++--- .../Annotations/AnnotationsTest.php | 4 +-- tests/IntegrationTest/BaseContainerTest.php | 6 ++--- .../CircularDependencyTest.php | 8 +++--- .../IntegrationTest/CompiledContainerTest.php | 7 ++--- tests/IntegrationTest/ContainerCallTest.php | 14 +++++----- tests/IntegrationTest/ContainerDebugTest.php | 23 +++++++++------- tests/IntegrationTest/ContainerHasTest.php | 1 - tests/IntegrationTest/ContainerMakeTest.php | 8 +++--- tests/IntegrationTest/ContainerSetTest.php | 1 - tests/IntegrationTest/DefaultEntriesTest.php | 1 - .../Definitions/AnnotationTest.php | 1 - .../Definitions/ArrayDefinitionTest.php | 7 ----- .../Definitions/AttributeTest.php | 4 --- .../Definitions/AutowireDefinitionTest.php | 21 ++------------- .../Definitions/CreateDefinitionTest.php | 3 ++- .../Definitions/DecoratorDefinitionTest.php | 5 ++-- .../EnvironmentVariableDefinitionTest.php | 3 ++- .../Definitions/FactoryDefinitionTest.php | 4 +-- .../Definitions/NestedDefinitionsTest.php | 12 ++++----- .../Definitions/StringDefinitionTest.php | 3 ++- .../Definitions/ValueDefinitionTest.php | 2 +- .../ErrorMessages/ErrorMessagesTest.php | 13 +++++----- tests/IntegrationTest/ProxyTest.php | 1 + tests/UnitTest/Annotation/InjectTest.php | 14 +++------- tests/UnitTest/ContainerBuilderTest.php | 1 - tests/UnitTest/ContainerGetTest.php | 4 +-- .../ArrayDefinitionExtensionTest.php | 6 ++--- .../Helper/AutowireDefinitionHelperTest.php | 6 ++--- .../Helper/CreateDefinitionHelperTest.php | 3 --- .../Helper/FactoryDefinitionHelperTest.php | 2 +- .../Definition/Resolver/ArrayResolverTest.php | 13 +++------- .../Resolver/DecoratorResolverTest.php | 13 +++------- .../EnvironmentVariableResolverTest.php | 21 ++++++--------- .../Resolver/FactoryParameterResolverTest.php | 19 +++----------- .../Resolver/FactoryResolverTest.php | 5 ++-- .../Resolver/InstanceInjectorTest.php | 2 +- .../Definition/Resolver/ObjectCreatorTest.php | 26 ++++++------------- .../Resolver/ResolverDispatcherTest.php | 13 +++------- .../Source/AnnotationBasedAutowiringTest.php | 4 +-- .../Definition/StringDefinitionTest.php | 3 ++- 48 files changed, 130 insertions(+), 215 deletions(-) diff --git a/src/Compiler/Compiler.php b/src/Compiler/Compiler.php index c5ed8bdba..b0864f172 100644 --- a/src/Compiler/Compiler.php +++ b/src/Compiler/Compiler.php @@ -163,7 +163,7 @@ public function compile( return $fileName; } - private function writeFileAtomic(string $fileName, string $content) : int + private function writeFileAtomic(string $fileName, string $content) : void { $tmpFile = @tempnam(dirname($fileName), 'swap-compile'); if ($tmpFile === false) { @@ -186,8 +186,6 @@ private function writeFileAtomic(string $fileName, string $content) : int @unlink($tmpFile); throw new InvalidArgumentException(sprintf('Error while renaming %s to %s', $tmpFile, $fileName)); } - - return $written; } /** @@ -354,10 +352,8 @@ private function isCompilable($value) : string | bool if ($value instanceof ValueDefinition) { return $this->isCompilable($value->getValue()); } - if ($value instanceof DecoratorDefinition) { - if (empty($value->getName())) { - return 'Decorators cannot be nested in another definition'; - } + if (($value instanceof DecoratorDefinition) && empty($value->getName())) { + return 'Decorators cannot be nested in another definition'; } // All other definitions are compilable if ($value instanceof Definition) { @@ -395,8 +391,6 @@ private function compileClosure(\Closure $closure) : string // $this, which makes sense since their code is copied into another class. $code = ($reflector->isStatic() ? '' : 'static ') . $reflector->getCode(); - $code = trim($code, "\t\n\r;"); - - return $code; + return trim($code, "\t\n\r;"); } } diff --git a/src/Definition/ObjectDefinition.php b/src/Definition/ObjectDefinition.php index a3db27fe6..206ef277f 100644 --- a/src/Definition/ObjectDefinition.php +++ b/src/Definition/ObjectDefinition.php @@ -189,9 +189,7 @@ public function replaceNestedDefinitions(callable $replacer) : void $propertyInjection->replaceNestedDefinition($replacer); }); - if ($this->constructorInjection) { - $this->constructorInjection->replaceNestedDefinitions($replacer); - } + $this->constructorInjection?->replaceNestedDefinitions($replacer); array_walk($this->methodInjections, function ($injectionArray) use ($replacer) { array_walk($injectionArray, function (MethodInjection $methodInjection) use ($replacer) { diff --git a/src/Definition/Source/AnnotationBasedAutowiring.php b/src/Definition/Source/AnnotationBasedAutowiring.php index 6412df020..4aae69288 100644 --- a/src/Definition/Source/AnnotationBasedAutowiring.php +++ b/src/Definition/Source/AnnotationBasedAutowiring.php @@ -227,7 +227,7 @@ private function getMethodParameter(int $parameterIndex, ReflectionParameter $pa // Look for the property type $parameterType = $parameter->getType(); - if ($parameterType && $parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) { + if ($parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) { return $parameterType->getName(); } diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php index 8e8ef7631..ad6bc8b68 100644 --- a/src/Definition/Source/AttributeBasedAutowiring.php +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -240,7 +240,7 @@ private function getMethodParameter(int $parameterIndex, ReflectionParameter $pa // Look for the property type $parameterType = $parameter->getType(); - if ($parameterType && $parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) { + if ($parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) { return $parameterType->getName(); } diff --git a/src/Definition/Source/DefinitionArray.php b/src/Definition/Source/DefinitionArray.php index cf6f880cb..6289f0fb1 100644 --- a/src/Definition/Source/DefinitionArray.php +++ b/src/Definition/Source/DefinitionArray.php @@ -68,9 +68,8 @@ public function getDefinition(string $name) : Definition | null // Look for the definition by name if (array_key_exists($name, $this->definitions)) { $definition = $this->definitions[$name]; - $definition = $this->normalizer->normalizeRootDefinition($definition, $name); - return $definition; + return $this->normalizer->normalizeRootDefinition($definition, $name); } // Build the cache of wildcard definitions @@ -90,9 +89,8 @@ public function getDefinition(string $name) : Definition | null $key = '#' . str_replace('\\' . self::WILDCARD, self::WILDCARD_PATTERN, $key) . '#'; if (preg_match($key, $name, $matches) === 1) { array_shift($matches); - $definition = $this->normalizer->normalizeRootDefinition($definition, $name, $matches); - return $definition; + return $this->normalizer->normalizeRootDefinition($definition, $name, $matches); } } diff --git a/src/Definition/Source/DefinitionFile.php b/src/Definition/Source/DefinitionFile.php index 0f36763e0..5b8290719 100644 --- a/src/Definition/Source/DefinitionFile.php +++ b/src/Definition/Source/DefinitionFile.php @@ -52,7 +52,7 @@ private function initialize() : void $definitions = require $this->file; if (! is_array($definitions)) { - throw new \Exception("File {$this->file} should return an array of definitions"); + throw new \Exception("File $this->file should return an array of definitions"); } $this->addDefinitions($definitions); diff --git a/src/Definition/StringDefinition.php b/src/Definition/StringDefinition.php index affe70360..6023777c9 100644 --- a/src/Definition/StringDefinition.php +++ b/src/Definition/StringDefinition.php @@ -80,7 +80,7 @@ public static function resolveExpression( } }; - $result = preg_replace_callback('#\{([^\{\}]+)\}#', $callback, $expression); + $result = preg_replace_callback('#\{([^{}]+)}#', $callback, $expression); if ($result === null) { throw new \RuntimeException(sprintf('An unknown error occurred while parsing the string definition: \'%s\'', $expression)); } diff --git a/src/Proxy/ProxyFactory.php b/src/Proxy/ProxyFactory.php index 6bb557568..562433741 100644 --- a/src/Proxy/ProxyFactory.php +++ b/src/Proxy/ProxyFactory.php @@ -42,9 +42,7 @@ public function __construct( */ public function createProxy(string $className, \Closure $initializer) : LazyLoadingInterface { - $proxyManager = $this->proxyManager(); - - return $proxyManager->createProxy($className, $initializer); + return $this->proxyManager()->createProxy($className, $initializer); } /** @@ -73,7 +71,7 @@ private function proxyManager() : LazyLoadingValueHolderFactory if ($this->proxyDirectory) { $config->setProxiesTargetDir($this->proxyDirectory); $config->setGeneratorStrategy(new FileWriterGeneratorStrategy(new FileLocator($this->proxyDirectory))); - // @phpstan-ignore-next-line + // @phpstan-ignore-next-line spl_autoload_register($config->getProxyAutoloader()); } else { $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); diff --git a/tests/IntegrationTest/Annotations/AnnotationsTest.php b/tests/IntegrationTest/Annotations/AnnotationsTest.php index 72caebcdc..74be91eec 100644 --- a/tests/IntegrationTest/Annotations/AnnotationsTest.php +++ b/tests/IntegrationTest/Annotations/AnnotationsTest.php @@ -5,8 +5,8 @@ namespace DI\Test\IntegrationTest\Annotations; use DI\ContainerBuilder; -use DI\Test\IntegrationTest\Annotations\InjectWithUseStatements\InjectWithUseStatements2; use DI\Test\IntegrationTest\BaseContainerTest; +use DI\DependencyException; /** * Test using annotations. @@ -98,7 +98,7 @@ public function inject_by_name(ContainerBuilder $builder) */ public function errors_if_dependency_by_name_not_found(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $builder->useAnnotations(true); $builder->build()->get(NamedInjection::class); } diff --git a/tests/IntegrationTest/BaseContainerTest.php b/tests/IntegrationTest/BaseContainerTest.php index bf5cf7e76..f3286c374 100644 --- a/tests/IntegrationTest/BaseContainerTest.php +++ b/tests/IntegrationTest/BaseContainerTest.php @@ -14,7 +14,7 @@ */ abstract class BaseContainerTest extends TestCase { - const COMPILATION_DIR = __DIR__ . '/tmp'; + public const COMPILATION_DIR = __DIR__ . '/tmp'; public static function setUpBeforeClass(): void { @@ -50,7 +50,7 @@ public function provideContainer() : array ]; } - protected static function generateCompiledClassName() + protected static function generateCompiledClassName(): string { return 'Container' . uniqid(); } @@ -64,7 +64,6 @@ protected static function assertEntryIsCompiled(Container $container, string $en return; } - /** @noinspection PhpUndefinedFieldInspection */ $compiledEntries = $container::METHOD_MAPPING; self::assertArrayHasKey($entry, $compiledEntries, "Entry $entry is not compiled"); } @@ -78,7 +77,6 @@ protected static function assertEntryIsNotCompiled(Container $container, string return; } - /** @noinspection PhpUndefinedFieldInspection */ $compiledEntries = $container::METHOD_MAPPING; self::assertArrayNotHasKey($entry, $compiledEntries, "Entry $entry is compiled"); } diff --git a/tests/IntegrationTest/CircularDependencyTest.php b/tests/IntegrationTest/CircularDependencyTest.php index 0dc7b2168..094de1493 100644 --- a/tests/IntegrationTest/CircularDependencyTest.php +++ b/tests/IntegrationTest/CircularDependencyTest.php @@ -5,11 +5,11 @@ namespace DI\Test\IntegrationTest; use DI\ContainerBuilder; -use DI\Test\IntegrationTest\BaseContainerTest; use DI\Test\UnitTest\Fixtures\Class1CircularDependencies; use DI\Test\UnitTest\Fixtures\Class2CircularDependencies; use function DI\create; use function DI\get; +use DI\DependencyException; /** * Test that circular dependencies are handled correctly. @@ -34,7 +34,7 @@ public function can_get_the_same_entry_twice(ContainerBuilder $builder) */ public function circular_dependencies_throw_exceptions(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Circular dependency detected while trying to resolve entry \'DI\Test\UnitTest\Fixtures\Class1CircularDependencies\''); $builder->addDefinitions([ Class1CircularDependencies::class => create() @@ -51,7 +51,7 @@ public function circular_dependencies_throw_exceptions(ContainerBuilder $builder */ public function circular_dependencies_with_annotations_throw_exceptions(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Circular dependency detected while trying to resolve entry \'DI\Test\UnitTest\Fixtures\Class1CircularDependencies\''); $builder->useAnnotations(true); $builder->build()->get(Class1CircularDependencies::class); @@ -63,7 +63,7 @@ public function circular_dependencies_with_annotations_throw_exceptions(Containe */ public function circular_dependencies_because_of_self_alias_throw_exceptions(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Circular dependency detected while trying to resolve entry \'foo\''); $builder->addDefinitions([ // Alias to itself -> infinite recursive loop diff --git a/tests/IntegrationTest/CompiledContainerTest.php b/tests/IntegrationTest/CompiledContainerTest.php index 376862a34..0cd3ddb0e 100644 --- a/tests/IntegrationTest/CompiledContainerTest.php +++ b/tests/IntegrationTest/CompiledContainerTest.php @@ -9,6 +9,7 @@ use function DI\create; use DI\Definition\Exception\InvalidDefinition; use function DI\get; +use DI\DependencyException; /** * Tests specific to the compiled container. @@ -61,7 +62,7 @@ public function the_container_is_compiled_once_and_never_recompiled_after() */ public function anonymous_classes_cannot_be_compiled() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Entry "foo" cannot be compiled: anonymous classes cannot be compiled'); $class = get_class(new class() { }); @@ -79,7 +80,7 @@ public function anonymous_classes_cannot_be_compiled() */ public function object_nested_in_other_definitions_cannot_be_compiled() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Entry "stdClass" cannot be compiled: An object was found but objects cannot be compiled'); $builder = new ContainerBuilder; $builder->addDefinitions([ @@ -95,7 +96,7 @@ public function object_nested_in_other_definitions_cannot_be_compiled() */ public function object_nested_in_arrays_cannot_be_compiled() { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while compiling foo. Error while compiling . Error while compiling . An object was found but objects cannot be compiled'); $builder = new ContainerBuilder; $builder->addDefinitions([ diff --git a/tests/IntegrationTest/ContainerCallTest.php b/tests/IntegrationTest/ContainerCallTest.php index 990c3c7b6..47879c4b8 100644 --- a/tests/IntegrationTest/ContainerCallTest.php +++ b/tests/IntegrationTest/ContainerCallTest.php @@ -5,6 +5,8 @@ namespace DI\Test\IntegrationTest; use DI\ContainerBuilder; +use Invoker\Exception\NotCallableException; +use Invoker\Exception\NotEnoughParametersException; /** * Tests the call() method from the container. @@ -149,7 +151,7 @@ public function calls_object_methods(ContainerBuilder $builder) */ public function creates_and_calls_class_methods_using_container(ContainerBuilder $builder) { - $class = __NAMESPACE__ . '\TestClass'; + $class = TestClass::class; $result = $builder->build()->call([$class, 'foo']); $this->assertEquals(42, $result); } @@ -160,7 +162,7 @@ public function creates_and_calls_class_methods_using_container(ContainerBuilder */ public function calls_static_methods(ContainerBuilder $builder) { - $class = __NAMESPACE__ . '\TestClass'; + $class = TestClass::class; $result = $builder->build()->call([$class, 'bar']); $this->assertEquals(24, $result); } @@ -171,7 +173,7 @@ public function calls_static_methods(ContainerBuilder $builder) */ public function calls_invokable_object(ContainerBuilder $builder) { - $class = __NAMESPACE__ . '\CallableTestClass'; + $class = CallableTestClass::class; $result = $builder->build()->call(new $class); $this->assertEquals(42, $result); } @@ -182,7 +184,7 @@ public function calls_invokable_object(ContainerBuilder $builder) */ public function creates_and_calls_invokable_objects_using_container(ContainerBuilder $builder) { - $result = $builder->build()->call(__NAMESPACE__ . '\CallableTestClass'); + $result = $builder->build()->call(CallableTestClass::class); $this->assertEquals(42, $result); } @@ -203,7 +205,7 @@ public function calls_functions(ContainerBuilder $builder) */ public function test_not_enough_parameters(ContainerBuilder $builder) { - $this->expectException('Invoker\Exception\NotEnoughParametersException'); + $this->expectException(NotEnoughParametersException::class); $this->expectExceptionMessage('Unable to invoke the callable because no value was given for parameter 1 ($foo)'); $builder->build()->call(function ($foo) { }); @@ -214,7 +216,7 @@ public function test_not_enough_parameters(ContainerBuilder $builder) */ public function test_not_callable(ContainerBuilder $builder) { - $this->expectException('Invoker\Exception\NotCallableException'); + $this->expectException(NotCallableException::class); $this->expectExceptionMessage('\'foo\' is neither a callable nor a valid container entry'); $builder->build()->call('foo'); } diff --git a/tests/IntegrationTest/ContainerDebugTest.php b/tests/IntegrationTest/ContainerDebugTest.php index eca1f3b02..702a7a716 100644 --- a/tests/IntegrationTest/ContainerDebugTest.php +++ b/tests/IntegrationTest/ContainerDebugTest.php @@ -6,6 +6,9 @@ use DI\Container; use DI\ContainerBuilder; +use DI\FactoryInterface; +use Psr\Container\ContainerInterface; +use Invoker\InvokerInterface; /** * Tests container debugging. @@ -15,10 +18,10 @@ class ContainerDebugTest extends BaseContainerTest public function testKnownEntries() { $expectedEntries = [ - 'DI\Container', - 'DI\FactoryInterface', - 'Invoker\InvokerInterface', - 'Psr\Container\ContainerInterface', + Container::class, + FactoryInterface::class, + InvokerInterface::class, + ContainerInterface::class, 'bar', 'foo', ]; @@ -26,7 +29,7 @@ public function testKnownEntries() $builder = new ContainerBuilder(); $builder->addDefinitions(['foo' => 'bar']); - /** @var \DI\Container $container */ + /** @var Container $container */ $container = $builder->build(); $container->set('bar', 'baz'); @@ -59,7 +62,7 @@ public function testEntriesDefinitions() 'null' => \DI\value(null), ]); - /** @var \DI\Container $container */ + /** @var Container $container */ $container = $builder->build(); $container->set('entry_object', new \stdClass()); @@ -74,18 +77,18 @@ public function testEntriesDefinitions() }); // Default definitions - $this->assertMatchesRegularExpression('/^Object \(\n {4}class = DI\\\Container\n/', $container->debugEntry('DI\Container')); + $this->assertMatchesRegularExpression('/^Object \(\n {4}class = DI\\\Container\n/', $container->debugEntry(Container::class)); $this->assertMatchesRegularExpression( '/^Object \(\n {4}class = #NOT INSTANTIABLE# DI\\\FactoryInterface\n/', - $container->debugEntry('DI\FactoryInterface') + $container->debugEntry(FactoryInterface::class) ); $this->assertMatchesRegularExpression( '/^Object \(\n {4}class = #NOT INSTANTIABLE# Invoker\\\InvokerInterface\n/', - $container->debugEntry('Invoker\InvokerInterface') + $container->debugEntry(InvokerInterface::class) ); $this->assertMatchesRegularExpression( '/^Object \(\n {4}class = #NOT INSTANTIABLE# Psr\\\Container\\\ContainerInterface\n/', - $container->debugEntry('Psr\Container\ContainerInterface') + $container->debugEntry(ContainerInterface::class) ); // Container definitions diff --git a/tests/IntegrationTest/ContainerHasTest.php b/tests/IntegrationTest/ContainerHasTest.php index fca951c0d..67eddbbf7 100644 --- a/tests/IntegrationTest/ContainerHasTest.php +++ b/tests/IntegrationTest/ContainerHasTest.php @@ -5,7 +5,6 @@ namespace DI\Test\IntegrationTest; use DI\ContainerBuilder; -use stdClass; /** * Tests the has() method from the container. diff --git a/tests/IntegrationTest/ContainerMakeTest.php b/tests/IntegrationTest/ContainerMakeTest.php index a8828a3ab..1e9a9563f 100644 --- a/tests/IntegrationTest/ContainerMakeTest.php +++ b/tests/IntegrationTest/ContainerMakeTest.php @@ -9,6 +9,8 @@ use DI\Test\UnitTest\Fixtures\PassByReferenceDependency; use DI\Test\UnitTest\Fixtures\Singleton; use stdClass; +use DI\DependencyException; +use DI\NotFoundException; /** * Test class for Container. @@ -31,7 +33,7 @@ public function testSetMake(ContainerBuilder $builder) */ public function testMakeNotFound(ContainerBuilder $builder) { - $this->expectException('DI\NotFoundException'); + $this->expectException(NotFoundException::class); $builder->build()->make('key'); } @@ -68,7 +70,7 @@ public function testCircularDependencies(ContainerBuilder $builder) */ public function testCircularDependencyException(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Circular dependency detected while trying to resolve entry \'DI\Test\UnitTest\Fixtures\Class1CircularDependencies\''); $builder->useAnnotations(true); $container = $builder->build(); @@ -80,7 +82,7 @@ public function testCircularDependencyException(ContainerBuilder $builder) */ public function testCircularDependencyExceptionWithAlias(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Circular dependency detected while trying to resolve entry \'foo\''); $builder->addDefinitions([ // Alias to itself -> infinite recursive loop diff --git a/tests/IntegrationTest/ContainerSetTest.php b/tests/IntegrationTest/ContainerSetTest.php index cbdb24e69..f2306261e 100644 --- a/tests/IntegrationTest/ContainerSetTest.php +++ b/tests/IntegrationTest/ContainerSetTest.php @@ -29,7 +29,6 @@ public function testSetNullValue(ContainerBuilder $builder) /** * @see https://github.com/mnapoli/PHP-DI/issues/126 - * @test * @dataProvider provideContainer */ public function testSetGetSetGet(ContainerBuilder $builder) diff --git a/tests/IntegrationTest/DefaultEntriesTest.php b/tests/IntegrationTest/DefaultEntriesTest.php index 2325630c1..24c4bf6c6 100644 --- a/tests/IntegrationTest/DefaultEntriesTest.php +++ b/tests/IntegrationTest/DefaultEntriesTest.php @@ -7,7 +7,6 @@ use DI\Container; use DI\ContainerBuilder; use DI\FactoryInterface; -use DI\Test\IntegrationTest\BaseContainerTest; use Invoker\InvokerInterface; use Psr\Container\ContainerInterface; diff --git a/tests/IntegrationTest/Definitions/AnnotationTest.php b/tests/IntegrationTest/Definitions/AnnotationTest.php index c831760cd..9b1143c27 100644 --- a/tests/IntegrationTest/Definitions/AnnotationTest.php +++ b/tests/IntegrationTest/Definitions/AnnotationTest.php @@ -7,7 +7,6 @@ use DI\ContainerBuilder; use DI\Test\IntegrationTest\BaseContainerTest; use DI\Test\IntegrationTest\Definitions\AnnotationTest\ConstructorInjection; -use DI\Test\IntegrationTest\Definitions\AnnotationTest\NamespacedClass; use DI\Test\IntegrationTest\Definitions\AnnotationTest\NonAnnotatedClass; use DI\Test\IntegrationTest\Definitions\AnnotationTest\PropertyInjection; use ProxyManager\Proxy\LazyLoadingInterface; diff --git a/tests/IntegrationTest/Definitions/ArrayDefinitionTest.php b/tests/IntegrationTest/Definitions/ArrayDefinitionTest.php index 36e3fb525..1f0ab1c38 100644 --- a/tests/IntegrationTest/Definitions/ArrayDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/ArrayDefinitionTest.php @@ -225,10 +225,3 @@ public function test_add_to_non_existing_array_works(ContainerBuilder $builder) $this->assertEquals('value 1', $array[0]); } } - -namespace DI\Test\IntegrationTest\Definitions\ArrayDefinitionTest; - -class SimpleClass -{ - public $dependency; -} diff --git a/tests/IntegrationTest/Definitions/AttributeTest.php b/tests/IntegrationTest/Definitions/AttributeTest.php index 039672f20..9540d038b 100644 --- a/tests/IntegrationTest/Definitions/AttributeTest.php +++ b/tests/IntegrationTest/Definitions/AttributeTest.php @@ -125,10 +125,6 @@ class NonAnnotatedClass { } -class NamespacedClass -{ -} - class AutowiredClass { public stdClass $entry; diff --git a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php index 74207ec7c..6f35f58bc 100644 --- a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php @@ -6,7 +6,6 @@ use DI\ContainerBuilder; use DI\Test\IntegrationTest\BaseContainerTest; -use DI\Test\IntegrationTest\Definitions\AutowireDefinition\OptionalParameterFollowedByRequiredParameter; use DI\Test\IntegrationTest\Definitions\AutowireDefinition\Php71; use DI\Test\IntegrationTest\Definitions\AutowireDefinitionTest\ConstructorInjection; use DI\Test\IntegrationTest\Definitions\AutowireDefinitionTest\LazyService; @@ -21,6 +20,7 @@ use function DI\autowire; use function DI\create; use function DI\get; +use DI\Definition\Exception\InvalidDefinition; /** * Test autowired definitions. @@ -296,7 +296,7 @@ public function test_setting_specific_method_parameter_overrides_autowiring(Cont */ public function test_cannot_use_autowire_if_autowiring_is_disabled(ContainerBuilder $builder) { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Cannot autowire entry "DI\Test\IntegrationTest\Definitions\ObjectDefinition\Class3" because autowiring is disabled'); $container = $builder ->useAutowiring(false) @@ -430,20 +430,3 @@ public function __construct( class LazyService { } - -class AllKindsOfInjections -{ - public $property; - public $constructorParameter; - public $methodParameter; - - public function __construct($constructorParameter) - { - $this->constructorParameter = $constructorParameter; - } - - public function method($methodParameter) - { - $this->methodParameter = $methodParameter; - } -} diff --git a/tests/IntegrationTest/Definitions/CreateDefinitionTest.php b/tests/IntegrationTest/Definitions/CreateDefinitionTest.php index 6383fd09f..79c3b515e 100644 --- a/tests/IntegrationTest/Definitions/CreateDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/CreateDefinitionTest.php @@ -18,6 +18,7 @@ use ProxyManager\Proxy\LazyLoadingInterface; use function DI\create; use function DI\get; +use DI\Definition\Exception\InvalidDefinition; /** * Test object definitions. @@ -186,7 +187,7 @@ public function test_has_entry(ContainerBuilder $builder) */ public function test_does_not_trigger_autowiring(ContainerBuilder $builder) { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Parameter $parameter of __construct() has no value defined or guessable'); $builder->useAutowiring(true); $builder->addDefinitions([ diff --git a/tests/IntegrationTest/Definitions/DecoratorDefinitionTest.php b/tests/IntegrationTest/Definitions/DecoratorDefinitionTest.php index 8149919a1..da4933f2e 100644 --- a/tests/IntegrationTest/Definitions/DecoratorDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/DecoratorDefinitionTest.php @@ -7,6 +7,7 @@ use DI\ContainerBuilder; use DI\Test\IntegrationTest\BaseContainerTest; use Psr\Container\ContainerInterface; +use DI\Definition\Exception\InvalidDefinition; /** * Test decorator definitions. @@ -121,7 +122,7 @@ public function test_multiple_decorators(ContainerBuilder $builder) */ public function test_decorate_must_have_previous_definition(ContainerBuilder $builder) { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Entry "foo" decorates nothing: no previous definition with the same name was found'); $builder->addDefinitions([ 'foo' => \DI\decorate(function ($previous) { @@ -137,7 +138,7 @@ public function test_decorate_must_have_previous_definition(ContainerBuilder $bu */ public function test_decorator_cannot_be_nested_in_another_definition(ContainerBuilder $builder) { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Definition "foo" contains an error: Decorators cannot be nested in another definition'); $builder->addDefinitions([ 'foo' => [ diff --git a/tests/IntegrationTest/Definitions/EnvironmentVariableDefinitionTest.php b/tests/IntegrationTest/Definitions/EnvironmentVariableDefinitionTest.php index 5b4e8d678..88bf5eb95 100644 --- a/tests/IntegrationTest/Definitions/EnvironmentVariableDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/EnvironmentVariableDefinitionTest.php @@ -6,6 +6,7 @@ use DI\ContainerBuilder; use DI\Test\IntegrationTest\BaseContainerTest; +use DI\Definition\Exception\InvalidDefinition; /** * Test environment variable definitions. @@ -38,7 +39,7 @@ public function test_existing_env_variable(ContainerBuilder $builder) */ public function test_nonexistent_env_variable(ContainerBuilder $builder) { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('The environment variable \'PHP_DI_DO_NOT_DEFINE_THIS\' has not been defined'); $builder->addDefinitions([ 'var' => \DI\env('PHP_DI_DO_NOT_DEFINE_THIS'), diff --git a/tests/IntegrationTest/Definitions/FactoryDefinitionTest.php b/tests/IntegrationTest/Definitions/FactoryDefinitionTest.php index fae42a0b0..7410b60a4 100644 --- a/tests/IntegrationTest/Definitions/FactoryDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/FactoryDefinitionTest.php @@ -39,7 +39,7 @@ public function test_closure_shortcut(ContainerBuilder $builder) $this->assertEquals('bar', $container->get('factory')); } - public function provideCallables() + public function provideCallables(): array { $callables = [ 'closure' => function () { @@ -531,7 +531,7 @@ public function test_closure_which_use_static_reference_cannot_be_compiled() $builder->build(); } - private function foo() + private function foo(): string { return 'hello'; } diff --git a/tests/IntegrationTest/Definitions/NestedDefinitionsTest.php b/tests/IntegrationTest/Definitions/NestedDefinitionsTest.php index 82891383f..c8249550f 100644 --- a/tests/IntegrationTest/Definitions/NestedDefinitionsTest.php +++ b/tests/IntegrationTest/Definitions/NestedDefinitionsTest.php @@ -24,11 +24,11 @@ public function should_allow_nested_definitions_in_environment_variables(Contain { $builder->addDefinitions([ 'foo' => 'bar', - 'link' => \DI\env('PHP_DI_DO_NOT_DEFINE_THIS', \DI\get('foo')), - 'object' => \DI\env('PHP_DI_DO_NOT_DEFINE_THIS', \DI\create('stdClass')), - 'objectInArray' => \DI\env('PHP_DI_DO_NOT_DEFINE_THIS', [\DI\create('stdClass')]), - 'autowired' => \DI\env('PHP_DI_DO_NOT_DEFINE_THIS', autowire(Autowireable::class)), - 'factory' => \DI\env('PHP_DI_DO_NOT_DEFINE_THIS', \DI\factory(function () { + 'link' => env('PHP_DI_DO_NOT_DEFINE_THIS', get('foo')), + 'object' => env('PHP_DI_DO_NOT_DEFINE_THIS', create('stdClass')), + 'objectInArray' => env('PHP_DI_DO_NOT_DEFINE_THIS', [create('stdClass')]), + 'autowired' => env('PHP_DI_DO_NOT_DEFINE_THIS', autowire(Autowireable::class)), + 'factory' => env('PHP_DI_DO_NOT_DEFINE_THIS', \DI\factory(function () { return 'hello'; })), ]); @@ -212,7 +212,7 @@ public function test_anonymous_functions_can_be_nested_in_other_definitions(Cont 'array' => [ function () { return 'hello'; }, ], - 'env' => \DI\env('PHP_DI_DO_NOT_DEFINE_THIS', function () { + 'env' => env('PHP_DI_DO_NOT_DEFINE_THIS', function () { return 'hello'; }), 'factory' => \DI\factory(function ($entry) { diff --git a/tests/IntegrationTest/Definitions/StringDefinitionTest.php b/tests/IntegrationTest/Definitions/StringDefinitionTest.php index 85222f46c..798a3672b 100644 --- a/tests/IntegrationTest/Definitions/StringDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/StringDefinitionTest.php @@ -6,6 +6,7 @@ use DI\ContainerBuilder; use DI\Test\IntegrationTest\BaseContainerTest; +use DI\DependencyException; /** * Test string definitions. @@ -75,7 +76,7 @@ public function test_nested_string_expressions(ContainerBuilder $builder) */ public function test_string_with_nonexistent_placeholder(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while parsing string expression for entry \'test-string\': No entry or class found for \'foo\''); $builder->addDefinitions([ 'test-string' => \DI\string('Hello {foo}'), diff --git a/tests/IntegrationTest/Definitions/ValueDefinitionTest.php b/tests/IntegrationTest/Definitions/ValueDefinitionTest.php index 4ef0e1e6e..b5c4dc41c 100644 --- a/tests/IntegrationTest/Definitions/ValueDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/ValueDefinitionTest.php @@ -36,7 +36,7 @@ public function test_value_definitions(ContainerBuilder $builder) $this->assertEquals(123, $container->get('int')); self::assertEntryIsNotCompiled($container, 'object'); - $this->assertEquals(new \stdClass(), $container->get('object')); + $this->assertEquals(new stdClass(), $container->get('object')); self::assertEntryIsCompiled($container, 'helper'); $this->assertEquals('foo', $container->get('helper')); diff --git a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php index 84d0e74f4..c21ca4462 100644 --- a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php +++ b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php @@ -8,6 +8,7 @@ use DI\Definition\Exception\InvalidDefinition; use DI\Test\IntegrationTest\BaseContainerTest; use function DI\autowire; +use DI\DependencyException; /** * Test error messages. @@ -84,7 +85,7 @@ class = DI\Test\IntegrationTest\ErrorMessages\Buggy1 $this->expectExceptionMessage($message); $builder->addDefinitions([ - Buggy1::class => \DI\autowire()->constructorParameter('foo', 'some value'), + Buggy1::class => autowire()->constructorParameter('foo', 'some value'), ]); $container = $builder->build(); @@ -96,7 +97,7 @@ class = DI\Test\IntegrationTest\ErrorMessages\Buggy1 */ public function test_constructor_injection_of_non_existent_container_entry(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while injecting dependencies into DI\Test\IntegrationTest\ErrorMessages\Buggy2: No entry or class found for \'nonExistentEntry\''); $builder->useAnnotations(true); $builder->build()->get(Buggy2::class); @@ -107,7 +108,7 @@ public function test_constructor_injection_of_non_existent_container_entry(Conta */ public function test_property_injection_of_non_existent_container_entry(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while injecting in DI\Test\IntegrationTest\ErrorMessages\Buggy3::dependency. No entry or class found for \'namedDependency\''); $builder->useAnnotations(true); $builder->build()->get(Buggy3::class); @@ -118,7 +119,7 @@ public function test_property_injection_of_non_existent_container_entry(Containe */ public function test_setter_injection_of_non_existent_container_entry(ContainerBuilder $builder) { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while injecting dependencies into DI\Test\IntegrationTest\ErrorMessages\Buggy4: No entry or class found for \'nonExistentBean\''); $builder->useAnnotations(true); $builder->build()->get(Buggy4::class); @@ -146,7 +147,7 @@ class = DI\Test\IntegrationTest\ErrorMessages\Buggy5 $builder->useAnnotations(true); $builder->addDefinitions([ - Buggy5::class => \DI\autowire(), + Buggy5::class => autowire(), ]); $builder->build()->get(Buggy5::class); @@ -157,7 +158,7 @@ class = DI\Test\IntegrationTest\ErrorMessages\Buggy5 */ public function test_factory_not_callable(ContainerBuilder $builder) { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Entry "foo" cannot be resolved: factory \'bar\' is neither a callable nor a valid container entry'); $builder->addDefinitions([ 'foo' => \DI\factory('bar'), diff --git a/tests/IntegrationTest/ProxyTest.php b/tests/IntegrationTest/ProxyTest.php index 55661b622..5b0aadbac 100644 --- a/tests/IntegrationTest/ProxyTest.php +++ b/tests/IntegrationTest/ProxyTest.php @@ -49,6 +49,7 @@ public function lazy_services_resolve_to_the_same_instance(ContainerBuilder $bui $proxy = $container->get('foo'); $this->assertSame($proxy, $container->get('foo')); // Resolve the proxy and check again + /** @noinspection PhpExpressionResultUnusedInspection */ $proxy->getValue(); $this->assertSame($proxy, $container->get('foo')); } diff --git a/tests/UnitTest/Annotation/InjectTest.php b/tests/UnitTest/Annotation/InjectTest.php index e5abafb9f..bf5d233d2 100644 --- a/tests/UnitTest/Annotation/InjectTest.php +++ b/tests/UnitTest/Annotation/InjectTest.php @@ -9,9 +9,9 @@ use DI\Test\UnitTest\Annotation\Fixtures\InjectFixture; use DI\Test\UnitTest\Annotation\Fixtures\MixedAnnotationsFixture; use DI\Test\UnitTest\Annotation\Fixtures\NonImportedInjectFixture; -use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader; use PHPUnit\Framework\TestCase; use ReflectionClass; +use DI\Definition\Exception\InvalidAnnotation; /** * Inject annotation test class. @@ -20,15 +20,9 @@ */ class InjectTest extends TestCase { - /** - * @var DoctrineAnnotationReader - */ - private $annotationReader; + private \Doctrine\Common\Annotations\Reader $annotationReader; - /** - * @var ReflectionClass - */ - private $reflectionClass; + private ReflectionClass $reflectionClass; public function setUp(): void { @@ -106,7 +100,7 @@ public function testMethod3() public function testInvalidAnnotation() { - $this->expectException('DI\Definition\Exception\InvalidAnnotation'); + $this->expectException(InvalidAnnotation::class); $this->expectExceptionMessage('@Inject({"param" = "value"}) expects "value" to be a string, [] given.'); $method = $this->reflectionClass->getMethod('method4'); $this->annotationReader->getMethodAnnotation($method, Inject::class); diff --git a/tests/UnitTest/ContainerBuilderTest.php b/tests/UnitTest/ContainerBuilderTest.php index 40011174a..816bb869a 100644 --- a/tests/UnitTest/ContainerBuilderTest.php +++ b/tests/UnitTest/ContainerBuilderTest.php @@ -5,7 +5,6 @@ namespace DI\Test\UnitTest; use DI\CompiledContainer; -use DI\Container; use DI\ContainerBuilder; use DI\Definition\Source\DefinitionArray; use DI\Definition\Source\SourceCache; diff --git a/tests/UnitTest/ContainerGetTest.php b/tests/UnitTest/ContainerGetTest.php index f855855ca..4bc9fc046 100644 --- a/tests/UnitTest/ContainerGetTest.php +++ b/tests/UnitTest/ContainerGetTest.php @@ -5,10 +5,10 @@ namespace DI\Test\UnitTest; use DI\Container; -use DI\ContainerBuilder; use DI\Test\UnitTest\Fixtures\PassByReferenceDependency; use PHPUnit\Framework\TestCase; use stdClass; +use DI\NotFoundException; /** * Test class for Container. @@ -27,7 +27,7 @@ public function testSetGet() public function testGetNotFound() { - $this->expectException('DI\NotFoundException'); + $this->expectException(NotFoundException::class); $container = new Container; $container->get('key'); } diff --git a/tests/UnitTest/Definition/ArrayDefinitionExtensionTest.php b/tests/UnitTest/Definition/ArrayDefinitionExtensionTest.php index 9b353db2b..d4f0cf7cb 100644 --- a/tests/UnitTest/Definition/ArrayDefinitionExtensionTest.php +++ b/tests/UnitTest/Definition/ArrayDefinitionExtensionTest.php @@ -8,15 +8,13 @@ use DI\Definition\ArrayDefinitionExtension; use DI\Definition\ValueDefinition; use PHPUnit\Framework\TestCase; +use DI\Definition\Exception\InvalidDefinition; /** * @covers \DI\Definition\ArrayDefinitionExtension */ class ArrayDefinitionExtensionTest extends TestCase { - /** - * @test - */ public function test_getters() { $definition = new ArrayDefinitionExtension(['hello']); @@ -47,7 +45,7 @@ public function should_append_values_after_sub_definitions_values() */ public function should_error_if_not_extending_an_array() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Definition name tries to add array entries but the previous definition is not an array'); $definition = new ArrayDefinitionExtension(['foo']); $definition->setName('name'); diff --git a/tests/UnitTest/Definition/Helper/AutowireDefinitionHelperTest.php b/tests/UnitTest/Definition/Helper/AutowireDefinitionHelperTest.php index 3a5df4f18..2f28e1749 100644 --- a/tests/UnitTest/Definition/Helper/AutowireDefinitionHelperTest.php +++ b/tests/UnitTest/Definition/Helper/AutowireDefinitionHelperTest.php @@ -8,15 +8,13 @@ use DI\Definition\ObjectDefinition\MethodInjection; use DI\Test\UnitTest\Definition\Helper\Fixtures\Class1; use PHPUnit\Framework\TestCase; +use DI\Definition\Exception\InvalidDefinition; /** * @covers \DI\Definition\Helper\AutowireDefinitionHelper */ class AutowireDefinitionHelperTest extends TestCase { - /** - * @test - */ public function test_default_config() { $helper = new AutowireDefinitionHelper(); @@ -176,7 +174,7 @@ public function should_update_constructor_definition_if_overriding_parameter_for public function test_error_message_on_unknown_parameter() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Parameter with name \'wrongName\' could not be found'); $helper = new AutowireDefinitionHelper(); $helper->methodParameter('__construct', 'wrongName', 42); diff --git a/tests/UnitTest/Definition/Helper/CreateDefinitionHelperTest.php b/tests/UnitTest/Definition/Helper/CreateDefinitionHelperTest.php index fca2273a6..d9e32cb24 100644 --- a/tests/UnitTest/Definition/Helper/CreateDefinitionHelperTest.php +++ b/tests/UnitTest/Definition/Helper/CreateDefinitionHelperTest.php @@ -12,9 +12,6 @@ */ class CreateDefinitionHelperTest extends TestCase { - /** - * @test - */ public function test_default_config() { $helper = new CreateDefinitionHelper(); diff --git a/tests/UnitTest/Definition/Helper/FactoryDefinitionHelperTest.php b/tests/UnitTest/Definition/Helper/FactoryDefinitionHelperTest.php index ab04bc1bb..da69f74ff 100644 --- a/tests/UnitTest/Definition/Helper/FactoryDefinitionHelperTest.php +++ b/tests/UnitTest/Definition/Helper/FactoryDefinitionHelperTest.php @@ -55,6 +55,6 @@ public function allows_to_define_method_parameters() $helper->parameter('foo', 'bar'); $definition = $helper->getDefinition('foo'); - $this->assertEquals($definition->getParameters(), ['foo' => 'bar']); + $this->assertEquals(['foo' => 'bar'], $definition->getParameters()); } } diff --git a/tests/UnitTest/Definition/Resolver/ArrayResolverTest.php b/tests/UnitTest/Definition/Resolver/ArrayResolverTest.php index 154a7b5e4..8d952417d 100644 --- a/tests/UnitTest/Definition/Resolver/ArrayResolverTest.php +++ b/tests/UnitTest/Definition/Resolver/ArrayResolverTest.php @@ -12,6 +12,7 @@ use EasyMock\EasyMock; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use DI\DependencyException; /** * @covers \DI\Definition\Resolver\ArrayResolver @@ -20,15 +21,9 @@ class ArrayResolverTest extends TestCase { use EasyMock; - /** - * @var DefinitionResolver|MockObject - */ - private $parentResolver; + private MockObject|DefinitionResolver $parentResolver; - /** - * @var ArrayResolver - */ - private $resolver; + private ArrayResolver $resolver; public function setUp(): void { @@ -94,7 +89,7 @@ public function resolve_should_preserve_keys() */ public function should_throw_with_a_nice_message() { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while resolving foo[0]. This is a message'); $this->parentResolver->expects($this->once()) ->method('resolve') diff --git a/tests/UnitTest/Definition/Resolver/DecoratorResolverTest.php b/tests/UnitTest/Definition/Resolver/DecoratorResolverTest.php index ace822d6b..fdcb67248 100644 --- a/tests/UnitTest/Definition/Resolver/DecoratorResolverTest.php +++ b/tests/UnitTest/Definition/Resolver/DecoratorResolverTest.php @@ -12,6 +12,7 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; +use DI\Definition\Exception\InvalidDefinition; /** * @covers \DI\Definition\Resolver\DecoratorResolver @@ -20,15 +21,9 @@ class DecoratorResolverTest extends TestCase { use EasyMock; - /** - * @var DecoratorResolver - */ - private $resolver; + private DecoratorResolver $resolver; - /** - * @var DefinitionResolver|MockObject - */ - private $parentResolver; + private MockObject|DefinitionResolver $parentResolver; public function setUp(): void { @@ -65,7 +60,7 @@ public function should_resolve_decorators() */ public function should_throw_if_the_factory_is_not_callable() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('The decorator "foo" is not callable'); $definition = new DecoratorDefinition('foo', 'Hello world'); diff --git a/tests/UnitTest/Definition/Resolver/EnvironmentVariableResolverTest.php b/tests/UnitTest/Definition/Resolver/EnvironmentVariableResolverTest.php index 34ff90851..9e18980ca 100644 --- a/tests/UnitTest/Definition/Resolver/EnvironmentVariableResolverTest.php +++ b/tests/UnitTest/Definition/Resolver/EnvironmentVariableResolverTest.php @@ -11,6 +11,7 @@ use EasyMock\EasyMock; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use DI\Definition\Exception\InvalidDefinition; /** * @covers \DI\Definition\Resolver\EnvironmentVariableResolver @@ -19,19 +20,13 @@ class EnvironmentVariableResolverTest extends TestCase { use EasyMock; - /** - * @var EnvironmentVariableResolver - */ - private $resolver; - /** - * @var DefinitionResolver|MockObject - */ - private $parentResolver; + private EnvironmentVariableResolver $resolver; + private MockObject|DefinitionResolver $parentResolver; - private $definedDefinition; - private $undefinedDefinition; - private $optionalDefinition; - private $nestedDefinition; + private EnvironmentVariableDefinition $definedDefinition; + private EnvironmentVariableDefinition $undefinedDefinition; + private EnvironmentVariableDefinition $optionalDefinition; + private EnvironmentVariableDefinition $nestedDefinition; public function setUp(): void { @@ -92,7 +87,7 @@ public function should_resolve_nested_definition_in_default_value() */ public function should_throw_if_undefined_env_variable_and_no_default() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('The environment variable \'UNDEFINED\' has not been defined'); $this->resolver->resolve($this->undefinedDefinition); } diff --git a/tests/UnitTest/Definition/Resolver/FactoryParameterResolverTest.php b/tests/UnitTest/Definition/Resolver/FactoryParameterResolverTest.php index 200ed4436..623265a17 100644 --- a/tests/UnitTest/Definition/Resolver/FactoryParameterResolverTest.php +++ b/tests/UnitTest/Definition/Resolver/FactoryParameterResolverTest.php @@ -20,20 +20,9 @@ class FactoryParameterResolverTest extends TestCase { use EasyMock; - /** - * @var FactoryParameterResolver - */ - private $resolver; - - /** - * @var ContainerInterface|MockObject - */ - private $container; - - /** - * @var RequestedEntry|MockObject - */ - private $requestedEntry; + private FactoryParameterResolver $resolver; + private MockObject|ContainerInterface $container; + private MockObject|RequestedEntry $requestedEntry; public function setUp(): void { @@ -136,7 +125,7 @@ public function should_not_overwrite_resolved_with_container_or_entry() $this->assertCount(3, $parameters); $this->assertSame($parameters[0], $mockContainer); $this->assertSame($parameters[1], $mockEntry); - $this->assertEquals($parameters[2], 'Foo'); + $this->assertEquals('Foo', $parameters[2]); } /** diff --git a/tests/UnitTest/Definition/Resolver/FactoryResolverTest.php b/tests/UnitTest/Definition/Resolver/FactoryResolverTest.php index b157b501d..5f383eda3 100644 --- a/tests/UnitTest/Definition/Resolver/FactoryResolverTest.php +++ b/tests/UnitTest/Definition/Resolver/FactoryResolverTest.php @@ -14,6 +14,7 @@ use EasyMock\EasyMock; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; +use DI\Definition\Exception\InvalidDefinition; /** * @covers \DI\Definition\Resolver\FactoryResolver @@ -61,7 +62,7 @@ public function should_inject_container() */ public function should_throw_if_the_factory_is_not_callable() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Entry "foo" cannot be resolved: factory \'Hello world\' is neither a callable nor a valid container entry'); $container = $this->easyMock(ContainerInterface::class); $resolver = new FactoryResolver($container, $this->easyMock(DefinitionResolver::class)); @@ -79,7 +80,7 @@ public function should_throw_if_the_factory_is_not_callable() */ public function should_throw_if_not_enough_parameters() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage('Entry "foo" cannot be resolved: Unable to invoke the callable because no value was given for parameter 3 ($c)'); $container = $this->easyMock(ContainerInterface::class); $resolver = new FactoryResolver($container, $this->easyMock(DefinitionResolver::class)); diff --git a/tests/UnitTest/Definition/Resolver/InstanceInjectorTest.php b/tests/UnitTest/Definition/Resolver/InstanceInjectorTest.php index e2371b8d1..f976a0af3 100644 --- a/tests/UnitTest/Definition/Resolver/InstanceInjectorTest.php +++ b/tests/UnitTest/Definition/Resolver/InstanceInjectorTest.php @@ -54,7 +54,7 @@ public function should_inject_methods_on_instance() $this->assertEquals('value', $instance->methodParam1); } - private function buildResolver() + private function buildResolver(): InstanceInjector { /** @var ResolverDispatcher $resolverDispatcher */ $resolverDispatcher = $this->easyMock(ResolverDispatcher::class); diff --git a/tests/UnitTest/Definition/Resolver/ObjectCreatorTest.php b/tests/UnitTest/Definition/Resolver/ObjectCreatorTest.php index 0f233c9e9..f7f71cfc8 100644 --- a/tests/UnitTest/Definition/Resolver/ObjectCreatorTest.php +++ b/tests/UnitTest/Definition/Resolver/ObjectCreatorTest.php @@ -17,6 +17,7 @@ use EasyMock\EasyMock; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use DI\Definition\Exception\InvalidDefinition; /** * @covers \DI\Definition\Resolver\ObjectCreator @@ -26,27 +27,16 @@ class ObjectCreatorTest extends TestCase { use EasyMock; - /** - * @var ProxyFactory|MockObject - */ - private $proxyFactory; + private MockObject|DefinitionResolver $parentResolver; - /** - * @var DefinitionResolver|MockObject - */ - private $parentResolver; - - /** - * @var ObjectCreator - */ - private $resolver; + private ObjectCreator $resolver; public function setUp(): void { - $this->proxyFactory = $this->easyMock(ProxyFactory::class); + $proxyFactory = $this->easyMock(ProxyFactory::class); $this->parentResolver = $this->easyMock(DefinitionResolver::class); - $this->resolver = new ObjectCreator($this->parentResolver, $this->proxyFactory); + $this->resolver = new ObjectCreator($this->parentResolver, $proxyFactory); } public function testResolve() @@ -182,7 +172,7 @@ public function testDefaultParameterValue() public function testUnknownClass() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $message = <<<'MESSAGE' Entry "foo" cannot be resolved: the class doesn't exist Full definition: @@ -200,7 +190,7 @@ class = #UNKNOWN# bar public function testNotInstantiable() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $message = <<<'MESSAGE' Entry "ArrayAccess" cannot be resolved: the class is not instantiable Full definition: @@ -218,7 +208,7 @@ class = #NOT INSTANTIABLE# ArrayAccess public function testUndefinedInjection() { - $this->expectException('DI\Definition\Exception\InvalidDefinition'); + $this->expectException(InvalidDefinition::class); $message = <<<'MESSAGE' Entry "DI\Test\UnitTest\Definition\Resolver\Fixture\FixtureClass" cannot be resolved: Parameter $param1 of __construct() has no value defined or guessable Full definition: diff --git a/tests/UnitTest/Definition/Resolver/ResolverDispatcherTest.php b/tests/UnitTest/Definition/Resolver/ResolverDispatcherTest.php index a91c00590..4bfa48297 100644 --- a/tests/UnitTest/Definition/Resolver/ResolverDispatcherTest.php +++ b/tests/UnitTest/Definition/Resolver/ResolverDispatcherTest.php @@ -20,18 +20,13 @@ class ResolverDispatcherTest extends TestCase { use EasyMock; - private $container; - private $proxyFactory; - /** - * @var ResolverDispatcher - */ - private $resolver; + private ResolverDispatcher $resolver; public function setUp(): void { - $this->container = $this->easyMock(ContainerInterface::class); - $this->proxyFactory = $this->easyMock(ProxyFactory::class); - $this->resolver = new ResolverDispatcher($this->container, $this->proxyFactory); + $container = $this->easyMock(ContainerInterface::class); + $proxyFactory = $this->easyMock(ProxyFactory::class); + $this->resolver = new ResolverDispatcher($container, $proxyFactory); } /** diff --git a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php b/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php index 82b27fdbe..61a1aefdb 100644 --- a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php +++ b/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php @@ -77,7 +77,7 @@ public function testTypedProperty() public function testScalarTypedPropertiesFail() { - $this->expectException(\DI\Definition\Exception\InvalidAnnotation::class); + $this->expectException(InvalidAnnotation::class); (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureScalarTypedProperty::class); } @@ -245,7 +245,7 @@ public function testReadParentPrivateProperties() $this->assertHasPropertyInjection($definition, 'propertyParentPrivate'); } - private function getMethodInjection(ObjectDefinition $definition, $name) + private function getMethodInjection(ObjectDefinition $definition, $name): ?MethodInjection { $methodInjections = $definition->getMethodInjections(); foreach ($methodInjections as $methodInjection) { diff --git a/tests/UnitTest/Definition/StringDefinitionTest.php b/tests/UnitTest/Definition/StringDefinitionTest.php index 190885039..3a6bba883 100644 --- a/tests/UnitTest/Definition/StringDefinitionTest.php +++ b/tests/UnitTest/Definition/StringDefinitionTest.php @@ -9,6 +9,7 @@ use EasyMock\EasyMock; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; +use DI\DependencyException; /** * @covers \DI\Definition\StringDefinition @@ -87,7 +88,7 @@ public function should_resolve_multiple_references() */ public function should_throw_on_unknown_entry_name() { - $this->expectException('DI\DependencyException'); + $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while parsing string expression for entry \'foo\': No entry or class found for \'test\''); $container = $this->easyMock(ContainerInterface::class, [ 'get' => new NotFoundException("No entry or class found for 'test'"), From 236f4346b3bd0684575a637d5828ba16f979c0f8 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 9 Apr 2022 19:37:26 +0200 Subject: [PATCH 34/45] Upgrade php-cs-fixer --- .gitignore | 2 +- .php-cs-fixer.php | 50 +++++++++++++++++ .php_cs | 53 ------------------- composer.json | 2 +- src/Annotation/Inject.php | 2 +- src/Annotation/Injectable.php | 2 +- src/Attribute/Inject.php | 4 +- src/Attribute/Injectable.php | 2 +- src/Compiler/Compiler.php | 2 +- src/Container.php | 2 +- src/ContainerBuilder.php | 2 +- src/Definition/FactoryDefinition.php | 4 +- .../Helper/AutowireDefinitionHelper.php | 4 +- .../Helper/FactoryDefinitionHelper.php | 2 +- src/Definition/Resolver/ArrayResolver.php | 2 +- .../Source/AnnotationBasedAutowiring.php | 6 +-- .../Source/AttributeBasedAutowiring.php | 4 +- src/Definition/Source/Autowiring.php | 2 +- src/Definition/Source/DefinitionArray.php | 2 +- src/Definition/Source/DefinitionFile.php | 2 +- src/Definition/Source/DefinitionSource.php | 2 +- src/Definition/Source/NoAutowiring.php | 2 +- .../Source/ReflectionBasedAutowiring.php | 4 +- src/Definition/Source/SourceCache.php | 2 +- src/Definition/Source/SourceChain.php | 2 +- src/functions.php | 4 +- 26 files changed, 82 insertions(+), 85 deletions(-) create mode 100644 .php-cs-fixer.php delete mode 100644 .php_cs diff --git a/.gitignore b/.gitignore index 0ea98fd19..029eb735c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,5 @@ /website/bower_components/ /website/css/all.min.css /logo/ -/.php_cs.cache +/.php-cs-fixer.cache /.phpunit.result.cache diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 000000000..3440d7d09 --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,50 @@ +in(__DIR__ . '/src') + ->notPath('Compiler/Template.php'); +$config = new PhpCsFixer\Config; + +return $config->setRules([ + '@PSR2' => true, + '@PHP70Migration' => true, + '@Symfony' => true, + '@Symfony:risky' => true, + 'array_syntax' => ['syntax' => 'short'], + 'braces' => [ + 'allow_single_line_closure' => true, + ], + 'concat_space' => [ + 'spacing' => 'one', + ], + //'declare_strict_types' => true, + 'heredoc_to_nowdoc' => true, + 'linebreak_after_opening_tag' => true, + 'new_with_braces' => false, + 'multiline_whitespace_before_semicolons' => true, + 'no_php4_constructor' => true, + 'no_unreachable_default_argument_value' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'ordered_imports' => true, + 'php_unit_strict' => true, + 'phpdoc_add_missing_param_annotation' => false, + 'phpdoc_align' => false, + 'phpdoc_annotation_without_dot' => false, + 'phpdoc_separation' => false, + 'phpdoc_to_comment' => false, + 'phpdoc_var_without_name' => true, + 'pow_to_exponentiation' => true, + 'unary_operator_spaces' => false, + 'return_type_declaration' => [ + 'space_before' => 'one', + ], + 'semicolon_after_instruction' => true, + 'strict_comparison' => true, + 'strict_param' => true, + 'yoda_style' => false, + 'native_function_invocation' => false, + 'single_line_throw' => false, +]) + ->setRiskyAllowed(true) + ->setFinder($finder); diff --git a/.php_cs b/.php_cs deleted file mode 100644 index 847680d77..000000000 --- a/.php_cs +++ /dev/null @@ -1,53 +0,0 @@ -in(__DIR__ . '/src') - ->notPath('Compiler/Template.php'); - -return PhpCsFixer\Config::create() - ->setRules([ - '@PSR2' => true, - '@PHP70Migration' => true, - '@Symfony' => true, - '@Symfony:risky' => true, - 'array_syntax' => ['syntax' => 'short'], - 'braces' => [ - 'allow_single_line_closure' => true, - ], - 'concat_space' => [ - 'spacing' => 'one', - ], - //'declare_strict_types' => true, - 'heredoc_to_nowdoc' => true, - 'is_null' => [ - 'use_yoda_style' => false, - ], - 'linebreak_after_opening_tag' => true, - 'new_with_braces' => false, - 'no_multiline_whitespace_before_semicolons' => true, - 'no_php4_constructor' => true, - 'no_unreachable_default_argument_value' => true, - 'no_useless_else' => true, - 'no_useless_return' => true, - 'ordered_imports' => true, - 'php_unit_strict' => true, - 'phpdoc_add_missing_param_annotation' => false, - 'phpdoc_align' => false, - 'phpdoc_annotation_without_dot' => false, - 'phpdoc_separation' => false, - 'phpdoc_to_comment' => false, - 'phpdoc_var_without_name' => true, - 'pow_to_exponentiation' => true, - 'unary_operator_spaces' => false, - 'return_type_declaration' => [ - 'space_before' => 'one', - ], - 'semicolon_after_instruction' => true, - 'strict_comparison' => true, - 'strict_param' => true, - 'yoda_style' => false, - 'native_function_invocation' => false, - 'single_line_throw' => false, - ]) - ->setRiskyAllowed(true) - ->setFinder($finder); diff --git a/composer.json b/composer.json index e2dc98301..4c5f82513 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "mnapoli/phpunit-easymock": "^1.3", "doctrine/annotations": "~1.10", "ocramius/proxy-manager": "^2.11.2", - "friendsofphp/php-cs-fixer": "^2.4", + "friendsofphp/php-cs-fixer": "^3", "vimeo/psalm": "^4.6" }, "provide": { diff --git a/src/Annotation/Inject.php b/src/Annotation/Inject.php index 12021ad3c..cc3f7d550 100644 --- a/src/Annotation/Inject.php +++ b/src/Annotation/Inject.php @@ -76,7 +76,7 @@ public function __construct(array $values) /** * @return string|null Name of the entry to inject */ - public function getName() : string | null + public function getName() : string|null { return $this->name; } diff --git a/src/Annotation/Injectable.php b/src/Annotation/Injectable.php index b35436582..ddab369bc 100644 --- a/src/Annotation/Injectable.php +++ b/src/Annotation/Injectable.php @@ -31,7 +31,7 @@ public function __construct(array $values) } } - public function isLazy() : bool | null + public function isLazy() : bool|null { return $this->lazy; } diff --git a/src/Attribute/Inject.php b/src/Attribute/Inject.php index 299d34e99..988cb738e 100644 --- a/src/Attribute/Inject.php +++ b/src/Attribute/Inject.php @@ -34,7 +34,7 @@ final class Inject /** * @throws InvalidAnnotation */ - public function __construct(string | array | null $name = null) + public function __construct(string|array|null $name = null) { // #[Inject('foo')] or #[Inject(name: 'foo')] if (is_string($name)) { @@ -59,7 +59,7 @@ public function __construct(string | array | null $name = null) /** * @return string|null Name of the entry to inject */ - public function getName() : string | null + public function getName() : string|null { return $this->name; } diff --git a/src/Attribute/Injectable.php b/src/Attribute/Injectable.php index 4bb46bd07..2acb78326 100644 --- a/src/Attribute/Injectable.php +++ b/src/Attribute/Injectable.php @@ -27,7 +27,7 @@ public function __construct( ) { } - public function isLazy() : bool | null + public function isLazy() : bool|null { return $this->lazy; } diff --git a/src/Compiler/Compiler.php b/src/Compiler/Compiler.php index b0864f172..b8ce6646a 100644 --- a/src/Compiler/Compiler.php +++ b/src/Compiler/Compiler.php @@ -347,7 +347,7 @@ private function createCompilationDirectory(string $directory) : void /** * @return string|true If true is returned that means that the value is compilable. */ - private function isCompilable($value) : string | bool + private function isCompilable($value) : string|bool { if ($value instanceof ValueDefinition) { return $this->isCompilable($value->getValue()); diff --git a/src/Container.php b/src/Container.php index ad202310a..24de4ada6 100644 --- a/src/Container.php +++ b/src/Container.php @@ -88,7 +88,7 @@ public static function create( * @param ContainerInterface $wrapperContainer If the container is wrapped by another container. */ public function __construct( - array | MutableDefinitionSource $definitions = [], + array|MutableDefinitionSource $definitions = [], ProxyFactory $proxyFactory = null, ContainerInterface $wrapperContainer = null ) { diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index 9ac2d8d0e..f27f6736d 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -289,7 +289,7 @@ public function wrapContainer(ContainerInterface $otherContainer) : self * or a DefinitionSource object. * @return $this */ - public function addDefinitions(string | array | DefinitionSource ...$definitions) : self + public function addDefinitions(string|array|DefinitionSource ...$definitions) : self { $this->ensureNotLocked(); diff --git a/src/Definition/FactoryDefinition.php b/src/Definition/FactoryDefinition.php index 06a5c3278..5044c910b 100644 --- a/src/Definition/FactoryDefinition.php +++ b/src/Definition/FactoryDefinition.php @@ -33,7 +33,7 @@ class FactoryDefinition implements Definition * @param callable|array|string $factory Callable that returns the value associated to the entry name. * @param array $parameters Parameters to be passed to the callable */ - public function __construct(string $name, callable | array | string $factory, array $parameters = []) + public function __construct(string $name, callable|array|string $factory, array $parameters = []) { $this->name = $name; $this->factory = $factory; @@ -53,7 +53,7 @@ public function setName(string $name) : void /** * @return callable|array|string Callable that returns the value associated to the entry name. */ - public function getCallable() : callable | array | string + public function getCallable() : callable|array|string { return $this->factory; } diff --git a/src/Definition/Helper/AutowireDefinitionHelper.php b/src/Definition/Helper/AutowireDefinitionHelper.php index fb2086d0d..7d548672c 100644 --- a/src/Definition/Helper/AutowireDefinitionHelper.php +++ b/src/Definition/Helper/AutowireDefinitionHelper.php @@ -28,7 +28,7 @@ class AutowireDefinitionHelper extends CreateDefinitionHelper * * @return $this */ - public function constructorParameter(string | int $parameter, mixed $value) : self + public function constructorParameter(string|int $parameter, mixed $value) : self { $this->constructor[$parameter] = $value; @@ -52,7 +52,7 @@ public function constructorParameter(string | int $parameter, mixed $value) : se * * @return $this */ - public function methodParameter(string $method, string | int $parameter, mixed $value) : self + public function methodParameter(string $method, string|int $parameter, mixed $value) : self { // Special case for the constructor if ($method === '__construct') { diff --git a/src/Definition/Helper/FactoryDefinitionHelper.php b/src/Definition/Helper/FactoryDefinitionHelper.php index 404044538..a6906c85a 100644 --- a/src/Definition/Helper/FactoryDefinitionHelper.php +++ b/src/Definition/Helper/FactoryDefinitionHelper.php @@ -26,7 +26,7 @@ class FactoryDefinitionHelper implements DefinitionHelper /** * @param bool $decorate Is the factory decorating a previous definition? */ - public function __construct(callable | array | string $factory, bool $decorate = false) + public function __construct(callable|array|string $factory, bool $decorate = false) { $this->factory = $factory; $this->decorate = $decorate; diff --git a/src/Definition/Resolver/ArrayResolver.php b/src/Definition/Resolver/ArrayResolver.php index a977716d7..3c8cd8bd9 100644 --- a/src/Definition/Resolver/ArrayResolver.php +++ b/src/Definition/Resolver/ArrayResolver.php @@ -58,7 +58,7 @@ public function isResolvable(Definition $definition, array $parameters = []) : b /** * @throws DependencyException */ - private function resolveDefinition(Definition $value, ArrayDefinition $definition, int | string $key) : mixed + private function resolveDefinition(Definition $value, ArrayDefinition $definition, int|string $key) : mixed { try { return $this->definitionResolver->resolve($value); diff --git a/src/Definition/Source/AnnotationBasedAutowiring.php b/src/Definition/Source/AnnotationBasedAutowiring.php index 4aae69288..1d01c4d84 100644 --- a/src/Definition/Source/AnnotationBasedAutowiring.php +++ b/src/Definition/Source/AnnotationBasedAutowiring.php @@ -37,7 +37,7 @@ class AnnotationBasedAutowiring implements DefinitionSource, Autowiring /** * @throws InvalidAnnotation */ - public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition|null { $className = $definition ? $definition->getClassName() : $name; @@ -65,7 +65,7 @@ public function autowire(string $name, ObjectDefinition $definition = null) : Ob * @throws InvalidAnnotation * @throws InvalidArgumentException The class doesn't exist */ - public function getDefinition(string $name) : ObjectDefinition | null + public function getDefinition(string $name) : ObjectDefinition|null { return $this->autowire($name); } @@ -210,7 +210,7 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection /** * @return string|null Entry name or null if not found. */ - private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters) : string | null + private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters) : string|null { // @Inject has definition for this parameter (by index, or by name) if (isset($annotationParameters[$parameterIndex])) { diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php index ad6bc8b68..b72d72d75 100644 --- a/src/Definition/Source/AttributeBasedAutowiring.php +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -38,7 +38,7 @@ public function __construct() /** * @throws InvalidAnnotation */ - public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition|null { $className = $definition ? $definition->getClassName() : $name; @@ -66,7 +66,7 @@ public function autowire(string $name, ObjectDefinition $definition = null) : Ob * @throws InvalidAnnotation * @throws InvalidArgumentException The class doesn't exist */ - public function getDefinition(string $name) : ObjectDefinition | null + public function getDefinition(string $name) : ObjectDefinition|null { return $this->autowire($name); } diff --git a/src/Definition/Source/Autowiring.php b/src/Definition/Source/Autowiring.php index 0471662e4..3b2da67cc 100644 --- a/src/Definition/Source/Autowiring.php +++ b/src/Definition/Source/Autowiring.php @@ -19,5 +19,5 @@ interface Autowiring * * @throws InvalidDefinition An invalid definition was found. */ - public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null; + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition|null; } diff --git a/src/Definition/Source/DefinitionArray.php b/src/Definition/Source/DefinitionArray.php index 6289f0fb1..74a04c144 100644 --- a/src/Definition/Source/DefinitionArray.php +++ b/src/Definition/Source/DefinitionArray.php @@ -63,7 +63,7 @@ public function addDefinition(Definition $definition) : void $this->wildcardDefinitions = null; } - public function getDefinition(string $name) : Definition | null + public function getDefinition(string $name) : Definition|null { // Look for the definition by name if (array_key_exists($name, $this->definitions)) { diff --git a/src/Definition/Source/DefinitionFile.php b/src/Definition/Source/DefinitionFile.php index 5b8290719..6c3d4355b 100644 --- a/src/Definition/Source/DefinitionFile.php +++ b/src/Definition/Source/DefinitionFile.php @@ -26,7 +26,7 @@ public function __construct( parent::__construct([], $autowiring); } - public function getDefinition(string $name) : Definition | null + public function getDefinition(string $name) : Definition|null { $this->initialize(); diff --git a/src/Definition/Source/DefinitionSource.php b/src/Definition/Source/DefinitionSource.php index f12a5f308..a7e48d57d 100644 --- a/src/Definition/Source/DefinitionSource.php +++ b/src/Definition/Source/DefinitionSource.php @@ -19,7 +19,7 @@ interface DefinitionSource * * @throws InvalidDefinition An invalid definition was found. */ - public function getDefinition(string $name) : Definition | null; + public function getDefinition(string $name) : Definition|null; /** * @return array Definitions indexed by their name. diff --git a/src/Definition/Source/NoAutowiring.php b/src/Definition/Source/NoAutowiring.php index 067daa629..73e4b6892 100644 --- a/src/Definition/Source/NoAutowiring.php +++ b/src/Definition/Source/NoAutowiring.php @@ -14,7 +14,7 @@ */ class NoAutowiring implements Autowiring { - public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition|null { throw new InvalidDefinition(sprintf( 'Cannot autowire entry "%s" because autowiring is disabled', diff --git a/src/Definition/Source/ReflectionBasedAutowiring.php b/src/Definition/Source/ReflectionBasedAutowiring.php index b3f5cc8e1..781269f1a 100644 --- a/src/Definition/Source/ReflectionBasedAutowiring.php +++ b/src/Definition/Source/ReflectionBasedAutowiring.php @@ -16,7 +16,7 @@ */ class ReflectionBasedAutowiring implements DefinitionSource, Autowiring { - public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition | null + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition|null { $className = $definition ? $definition->getClassName() : $name; @@ -37,7 +37,7 @@ public function autowire(string $name, ObjectDefinition $definition = null) : Ob return $definition; } - public function getDefinition(string $name) : ObjectDefinition | null + public function getDefinition(string $name) : ObjectDefinition|null { return $this->autowire($name); } diff --git a/src/Definition/Source/SourceCache.php b/src/Definition/Source/SourceCache.php index 8501f41e0..ea2dd559f 100644 --- a/src/Definition/Source/SourceCache.php +++ b/src/Definition/Source/SourceCache.php @@ -21,7 +21,7 @@ public function __construct( ) { } - public function getDefinition(string $name) : Definition | null + public function getDefinition(string $name) : Definition|null { $definition = apcu_fetch($this->getCacheKey($name)); diff --git a/src/Definition/Source/SourceChain.php b/src/Definition/Source/SourceChain.php index 1eec6a1ea..c88fa40b6 100644 --- a/src/Definition/Source/SourceChain.php +++ b/src/Definition/Source/SourceChain.php @@ -30,7 +30,7 @@ public function __construct( * @param int $startIndex Use this parameter to start looking from a specific * point in the source chain. */ - public function getDefinition(string $name, int $startIndex = 0) : Definition | null + public function getDefinition(string $name, int $startIndex = 0) : Definition|null { $count = count($this->sources); for ($i = $startIndex; $i < $count; ++$i) { diff --git a/src/functions.php b/src/functions.php index a6979a6db..43aa9d93b 100644 --- a/src/functions.php +++ b/src/functions.php @@ -56,7 +56,7 @@ function autowire(?string $className = null) : AutowireDefinitionHelper * @param callable|array|string $factory The factory is a callable that takes the container as parameter * and returns the value to register in the container. */ - function factory(callable | array | string $factory) : FactoryDefinitionHelper + function factory(callable|array|string $factory) : FactoryDefinitionHelper { return new FactoryDefinitionHelper($factory); } @@ -75,7 +75,7 @@ function factory(callable | array | string $factory) : FactoryDefinitionHelper * @param callable $callable The callable takes the decorated object as first parameter and * the container as second. */ - function decorate(callable | array | string $callable) : FactoryDefinitionHelper + function decorate(callable|array|string $callable) : FactoryDefinitionHelper { return new FactoryDefinitionHelper($callable, true); } From 1117da70ef6a0a86606fa93cc2a5777119f31908 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 9 Apr 2022 19:37:50 +0200 Subject: [PATCH 35/45] Force strict types --- .php-cs-fixer.php | 2 +- src/Definition/Source/SourceCache.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 3440d7d09..009f1557a 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -17,7 +17,7 @@ 'concat_space' => [ 'spacing' => 'one', ], - //'declare_strict_types' => true, + 'declare_strict_types' => true, 'heredoc_to_nowdoc' => true, 'linebreak_after_opening_tag' => true, 'new_with_braces' => false, diff --git a/src/Definition/Source/SourceCache.php b/src/Definition/Source/SourceCache.php index ea2dd559f..3cdf77744 100644 --- a/src/Definition/Source/SourceCache.php +++ b/src/Definition/Source/SourceCache.php @@ -1,5 +1,7 @@ Date: Sat, 9 Apr 2022 19:45:03 +0200 Subject: [PATCH 36/45] Improve code style --- .php-cs-fixer.php | 4 ++++ src/Compiler/Compiler.php | 14 +++++++------- src/Compiler/ObjectCreationCompiler.php | 18 +++++++++--------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 009f1557a..ba325f0b6 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -8,6 +8,10 @@ return $config->setRules([ '@PSR2' => true, '@PHP70Migration' => true, + '@PHP71Migration' => true, + '@PHP73Migration' => true, + '@PHP74Migration' => true, + '@PHP80Migration' => true, '@Symfony' => true, '@Symfony:risky' => true, 'array_syntax' => ['syntax' => 'short'], diff --git a/src/Compiler/Compiler.php b/src/Compiler/Compiler.php index b8ce6646a..fd61fe974 100644 --- a/src/Compiler/Compiler.php +++ b/src/Compiler/Compiler.php @@ -222,13 +222,13 @@ private function compileDefinition(string $entryName, Definition $definition) : $isOptional = $this->compileValue($definition->isOptional()); $defaultValue = $this->compileValue($definition->getDefaultValue()); $code = <<getVariableName()}' has not been defined"); - } - return $defaultValue; -PHP; + \$value = \$_ENV[$variableName] ?? \$_SERVER[$variableName] ?? getenv($variableName); + if (false !== \$value) return \$value; + if (!$isOptional) { + throw new \DI\Definition\Exception\InvalidDefinition("The environment variable '{$definition->getVariableName()}' has not been defined"); + } + return $defaultValue; + PHP; break; case $definition instanceof ArrayDefinition: try { diff --git a/src/Compiler/ObjectCreationCompiler.php b/src/Compiler/ObjectCreationCompiler.php index 9d165eefa..2bc0bb971 100644 --- a/src/Compiler/ObjectCreationCompiler.php +++ b/src/Compiler/ObjectCreationCompiler.php @@ -140,15 +140,15 @@ private function compileLazyDefinition(ObjectDefinition $definition) : string $this->compiler->getProxyFactory()->generateProxyClass($className); return <<proxyFactory->createProxy( - '{$definition->getClassName()}', - function (&\$wrappedObject, \$proxy, \$method, \$params, &\$initializer) { - \$wrappedObject = $subDefinition; - \$initializer = null; // turning off further lazy initialization - return true; - } - ); -STR; + \$object = \$this->proxyFactory->createProxy( + '{$definition->getClassName()}', + function (&\$wrappedObject, \$proxy, \$method, \$params, &\$initializer) { + \$wrappedObject = $subDefinition; + \$initializer = null; // turning off further lazy initialization + return true; + } + ); + STR; } /** From c3891b0b7e0d6c06e12417cd28911c02c28790dc Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 9 Apr 2022 20:26:45 +0200 Subject: [PATCH 37/45] Drop support for `@Inject` annotations in favor of attributes --- .php-cs-fixer.php | 3 +- composer.json | 2 - couscous.yml | 2 +- doc/README.md | 2 +- doc/annotations.md | 146 +--------- doc/container-configuration.md | 4 +- doc/container.md | 6 +- doc/definition-overriding.md | 16 +- doc/definition.md | 8 +- doc/frameworks/silex.md | 2 +- doc/frameworks/slim.md | 2 +- doc/frameworks/symfony2.md | 12 +- doc/frameworks/zf1.md | 6 +- doc/frameworks/zf2.md | 18 +- doc/getting-started.md | 4 +- doc/lazy-injection.md | 8 +- doc/migration/7.0.md | 30 +- doc/performances.md | 8 +- doc/php-definitions.md | 2 +- src/Annotation/Inject.php | 91 ------ src/Annotation/Injectable.php | 38 --- src/Attribute/Inject.php | 8 +- src/Attribute/Injectable.php | 2 +- src/ContainerBuilder.php | 26 +- ...lidAnnotation.php => InvalidAttribute.php} | 4 +- .../Helper/AutowireDefinitionHelper.php | 8 +- .../Helper/FactoryDefinitionHelper.php | 2 +- .../Source/AnnotationBasedAutowiring.php | 273 ------------------ .../Source/AttributeBasedAutowiring.php | 27 +- tests/IntegrationTest/Annotations/A.php | 9 - .../Annotations/AnnotationsTest.php | 105 ------- tests/IntegrationTest/Annotations/B.php | 35 --- tests/IntegrationTest/Annotations/C.php | 9 - tests/IntegrationTest/Annotations/Child.php | 20 -- tests/IntegrationTest/Annotations/D.php | 9 - .../Annotations/NamedInjection.php | 15 - .../CircularDependencyTest.php | 4 +- .../IntegrationTest/ContainerInjectOnTest.php | 21 +- tests/IntegrationTest/ContainerMakeTest.php | 2 +- .../Definitions/AnnotationTest.php | 189 ------------ .../ConstructorInjection.php | 6 +- .../AutowireDefinition/MethodInjection.php | 6 +- .../Definitions/AutowireDefinitionTest.php | 4 +- .../Definitions/WildcardDefinitionsTest.php | 8 +- .../IntegrationTest/ErrorMessages/Buggy2.php | 7 +- .../IntegrationTest/ErrorMessages/Buggy3.php | 6 +- .../IntegrationTest/ErrorMessages/Buggy4.php | 6 +- .../IntegrationTest/ErrorMessages/Buggy5.php | 6 +- .../ErrorMessages/ErrorMessagesTest.php | 10 +- tests/IntegrationTest/Fixtures/Class1.php | 41 +-- .../Fixtures/InheritanceTest/BaseClass.php | 10 +- .../Fixtures/InheritanceTest/SubClass.php | 6 +- tests/IntegrationTest/Fixtures/Interface1.php | 4 +- .../Fixtures/LazyDependency.php | 9 +- tests/IntegrationTest/InheritanceTest.php | 12 +- .../IntegrationTest/Issues/Issue72/Class1.php | 6 +- tests/IntegrationTest/Issues/Issue72Test.php | 10 +- tests/PerformanceTest/autowire.php | 2 +- tests/PerformanceTest/call.php | 2 +- tests/PerformanceTest/factory.php | 2 +- tests/PerformanceTest/get-cache.php | 2 +- tests/PerformanceTest/get-object.php | 2 +- tests/PerformanceTest/get.php | 2 +- .../Annotation/Fixtures/Dependency.php | 9 - .../Annotation/Fixtures/InjectFixture.php | 54 ---- .../Annotation/Fixtures/Injectable1.php | 12 - .../Annotation/Fixtures/Injectable2.php | 12 - .../Fixtures/MixedAnnotationsFixture.php | 17 -- .../Fixtures/NonImportedInjectFixture.php | 13 - tests/UnitTest/Annotation/InjectTest.php | 134 --------- tests/UnitTest/Annotation/InjectableTest.php | 52 ---- tests/UnitTest/Attributes/InjectTest.php | 4 +- tests/UnitTest/ContainerBuilderTest.php | 4 +- ...t.php => AttributeBasedAutowiringTest.php} | 78 +++-- .../Source/Fixtures/AnnotationFixture3.php | 6 +- .../Source/Fixtures/AnnotationFixture4.php | 6 +- .../Source/Fixtures/AnnotationFixture5.php | 6 +- .../Fixtures/AnnotationFixtureChild.php | 10 +- .../Fixtures/AnnotationFixtureParent.php | 14 +- .../AnnotationFixtureScalarTypedProperty.php | 6 +- .../AnnotationFixtureTypedProperties.php | 10 +- .../Fixtures/AnnotationInjectableFixture.php | 6 +- ...tationFixture.php => AttributeFixture.php} | 48 +-- .../Fixtures/Class1CircularDependencies.php | 6 +- .../Fixtures/Class2CircularDependencies.php | 7 +- tests/UnitTest/Fixtures/Singleton.php | 6 +- 86 files changed, 255 insertions(+), 1612 deletions(-) delete mode 100644 src/Annotation/Inject.php delete mode 100644 src/Annotation/Injectable.php rename src/Definition/Exception/{InvalidAnnotation.php => InvalidAttribute.php} (57%) delete mode 100644 src/Definition/Source/AnnotationBasedAutowiring.php delete mode 100644 tests/IntegrationTest/Annotations/A.php delete mode 100644 tests/IntegrationTest/Annotations/AnnotationsTest.php delete mode 100644 tests/IntegrationTest/Annotations/B.php delete mode 100644 tests/IntegrationTest/Annotations/C.php delete mode 100644 tests/IntegrationTest/Annotations/Child.php delete mode 100644 tests/IntegrationTest/Annotations/D.php delete mode 100644 tests/IntegrationTest/Annotations/NamedInjection.php delete mode 100644 tests/IntegrationTest/Definitions/AnnotationTest.php delete mode 100644 tests/UnitTest/Annotation/Fixtures/Dependency.php delete mode 100644 tests/UnitTest/Annotation/Fixtures/InjectFixture.php delete mode 100644 tests/UnitTest/Annotation/Fixtures/Injectable1.php delete mode 100644 tests/UnitTest/Annotation/Fixtures/Injectable2.php delete mode 100644 tests/UnitTest/Annotation/Fixtures/MixedAnnotationsFixture.php delete mode 100644 tests/UnitTest/Annotation/Fixtures/NonImportedInjectFixture.php delete mode 100644 tests/UnitTest/Annotation/InjectTest.php delete mode 100644 tests/UnitTest/Annotation/InjectableTest.php rename tests/UnitTest/Definition/Source/{AnnotationBasedAutowiringTest.php => AttributeBasedAutowiringTest.php} (72%) rename tests/UnitTest/Definition/Source/Fixtures/{AnnotationFixture.php => AttributeFixture.php} (67%) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index ba325f0b6..bdeaf4aca 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -31,7 +31,7 @@ 'no_useless_else' => true, 'no_useless_return' => true, 'ordered_imports' => true, - 'php_unit_strict' => true, + 'php_unit_strict' => false, 'phpdoc_add_missing_param_annotation' => false, 'phpdoc_align' => false, 'phpdoc_annotation_without_dot' => false, @@ -49,6 +49,7 @@ 'yoda_style' => false, 'native_function_invocation' => false, 'single_line_throw' => false, + 'php_unit_method_casing' => false, ]) ->setRiskyAllowed(true) ->setFinder($finder); diff --git a/composer.json b/composer.json index 4c5f82513..4e60d9874 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,6 @@ "require-dev": { "phpunit/phpunit": "^9.5", "mnapoli/phpunit-easymock": "^1.3", - "doctrine/annotations": "~1.10", "ocramius/proxy-manager": "^2.11.2", "friendsofphp/php-cs-fixer": "^3", "vimeo/psalm": "^4.6" @@ -41,7 +40,6 @@ "psr/container-implementation": "^1.0" }, "suggest": { - "doctrine/annotations": "Install it if you want to use annotations (version ^1.7)", "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ^2.3)" } } diff --git a/couscous.yml b/couscous.yml index a13ece865..68689f3b7 100644 --- a/couscous.yml +++ b/couscous.yml @@ -47,7 +47,7 @@ menu: text: PHP definitions url: doc/php-definitions.html attributes: - text: PHP 8 attributes + text: PHP attributes url: doc/attributes.html annotations: text: Annotations diff --git a/doc/README.md b/doc/README.md index 44abbdc75..cc9286a8c 100644 --- a/doc/README.md +++ b/doc/README.md @@ -19,7 +19,7 @@ title: Documentation index * [Introduction](definition.md) * [Autowiring](autowiring.md) * [PHP definitions](php-definitions.md) -* [Annotations](annotations.md) +* [Attributes](attributes.md) * [Definition extensions and overriding](definition-overriding.md) ### Frameworks integration diff --git a/doc/annotations.md b/doc/annotations.md index daa88824d..6744bd0a7 100644 --- a/doc/annotations.md +++ b/doc/annotations.md @@ -5,148 +5,4 @@ current_menu: annotations # Annotations -**Since PHP 8, annotations are deprecated in favor of [PHP attributes](attributes.md).** - ---- - -On top of [autowiring](autowiring.md) and [PHP configuration files](php-definitions.md), you can define injections using annotations. - -Using annotations do not affect performances when [compiling the container](performances.md). - -## Installation - -Annotations **are disabled by default**. To be able to use them, you first need to install the [Doctrine Annotations](http://doctrine-common.readthedocs.org/en/latest/reference/annotations.html) library using Composer: - -``` -composer require doctrine/annotations -``` - -Then you need to [configure the `ContainerBuilder`](container-configuration.md) to use them: - -```php -$containerBuilder->useAnnotations(true); -``` - -Annotations are written in PHP docblock comments. They are used by a lot of modern libraries and frameworks, like [Doctrine](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html), [Symfony](http://symfony.com/) and more. - -## @Inject - -`@Inject` lets you define where PHP-DI should inject something, and optionally what it should inject. - -It can be used on: - -- the constructor (constructor injection) -- methods (setter/method injection) -- properties (property injection) - -*Note: property injections occur after the constructor is executed, so any injectable property will be null inside `__construct`.* - -**Since PHP-DI 7, `@Inject` will ignore types declared in phpdoc. Only types specified in PHP code will be considered.** - -Here is an example of all possible uses of the `@Inject` annotation: - -```php -class Example -{ - /** - * Annotation combined with a type on the property: - * - * @Inject - */ - private Foo $property1; - - /** - * Explicit definition of the entry to inject: - * - * @Inject("db.host") - */ - private $property2; - - /** - * Annotation specifying exactly what to inject: - * - * @Inject({"db.host", "db.name"}) - */ - public function __construct($param1, $param2) - { - } - - /** - * Annotation combined with PHP types: - * - * @Inject - */ - public function method1(Foo $param) - { - } - - /** - * Explicit definition of the entries to inject: - * - * @Inject({"db.host", "db.name"}) - */ - public function method2($param1, $param2) - { - } - - /** - * Explicit definition of parameters by their name - * (types are used for the other parameters): - * - * @Inject({"param2" = "db.host"}) - */ - public function method3(Foo $param1, $param2) - { - } -} -``` - -*Note: importing annotations with `use DI\Annotation\Inject;` is optional.* - -### Troubleshooting @Inject - -- you must use double quotes (`"`) instead of single quotes(`'`), for example: `@Inject("foo")` -- what's inside `@Inject()` must be in quotes, even if it's a class name: `@Inject("Acme\Blog\ArticleRepository")` -- `@Inject` is not meant to be used on the method to call with [`Container::call()`](container.md#call) (it will be ignored) -- **Since PHP-DI 7, `@Inject` will ignore types declared in phpdoc. Only types specified in PHP code will be considered.** - -Note that `@Inject` is implicit on all constructors. - -## Injectable - -The `@Injectable` annotation lets you set options on injectable classes: - -```php -/** - * @Injectable(lazy=true) - */ -class Example -{ -} -``` - -**The `@Injectable` annotation is optional: by default, all classes are injectable.** - -## Limitations - -There are things that can't be defined with annotations: - -- values (instead of classes) -- mapping interfaces to implementations -- defining entries with an anonymous function - -For that, you can combine annotations with [definitions in PHP](php-definitions.md). - -## Troubleshooting - -Since annotations are in PHP docblocks, the opcache option `opcache.save_comments` must be set to `1`. If it is set to `0`, comments will be stripped from the source code and annotations will not work. - -The default value for this option is `1` so everything should work by default. - -To check the value of this option, you can run the following command: - -``` -$ php -i | grep "opcache.save_comments" -``` - -Furthermore, please mind that annotations are case-sensitive. You should write `@Inject` and `@Injectable` instead of `@inject` and `@injectable` to avoid bugs on certain systems. +**Since PHP-DI 7, annotations have been replaced by [PHP attributes](attributes.md).** diff --git a/doc/container-configuration.md b/doc/container-configuration.md index 5d0311eca..9470b57e6 100644 --- a/doc/container-configuration.md +++ b/doc/container-configuration.md @@ -13,7 +13,7 @@ PHP-DI's container is preconfigured for "plug and play". You can start using it $container = new Container(); ``` -By default, [Autowiring](definition.md) will be enabled. [Annotations](annotations.md) are disabled by default. +By default, [Autowiring](definition.md) will be enabled. [Attributes](attributes.md) are disabled by default. To register [definitions using an array](php-definitions.md): @@ -51,7 +51,7 @@ If you want to use PHP-DI's container as a simple container (no autowiring or an ```php $builder = new \DI\ContainerBuilder(); $builder->useAutowiring(false); -$builder->useAnnotations(false); +$builder->useAttributes(false); $container = $builder->build(); ``` diff --git a/doc/container.md b/doc/container.md index a08546545..a5921b173 100644 --- a/doc/container.md +++ b/doc/container.md @@ -188,9 +188,7 @@ Example: ```php class UserController extends BaseController { - /** - * @Inject - */ + #[Inject] private SomeService $someService; public function __construct() @@ -207,7 +205,7 @@ class UserController extends BaseController ``` As you might have guessed, you can't use constructor injection with this method. -But other kind of injections (property or setter) will work, whether you use annotations +But other kind of injections (property or setter) will work, whether you use attributes or whether you configured your object in a definition file. ## Extending the container diff --git a/doc/definition-overriding.md b/doc/definition-overriding.md index 37c4ae2e5..e576782e4 100644 --- a/doc/definition-overriding.md +++ b/doc/definition-overriding.md @@ -5,7 +5,7 @@ current_menu: definition-overriding # Definition extensions and overriding -A simple application usually takes advantage of one or two *definition sources*: autowiring (or annotations) + a definition file/array. +A simple application usually takes advantage of one or two *definition sources*: autowiring (with or without attributes) + a definition file/array. However in more complex applications or modular systems you might want to have multiple definition files (e.g. one per modules/bundles/plugins/…). In this case, PHP-DI provides a clear and powerful system to **override and/or extend definitions**. @@ -14,7 +14,7 @@ However in more complex applications or modular systems you might want to have m From the lowest priority to the highest: - autowiring if enabled -- annotations if enabled +- attributes if enabled - PHP definitions (file or array) in the order they were added - definitions added straight in the container with `$container->set()` @@ -29,21 +29,21 @@ class Foo } ``` -PHP-DI would inject an instance of `Bar` using autowiring. Annotations have a higher priority, we can use it to override the definition: +PHP-DI would inject an instance of `Bar` using autowiring. Attributes have a higher priority, we can use it to override the definition: ```php +use DI\Attribute\Inject; + class Foo { - /** - * @Inject({"my.specific.service"}) - */ + #[Inject(['my.specific.service'])] public function __construct(Bar $param1) { } } ``` -You can go even further by overriding annotations and autowiring using file-based definitions: +You can go even further by overriding attributes and autowiring using file-based definitions: ```php return [ @@ -61,7 +61,7 @@ If we had another definition file (registered after this one), we could override `DI\create()` overrides completely any previous definition or even autowiring. It doesn't allow extending another definition. See the "decorators" section below if you want to do that. -If an object is built using autowiring (or annotations), you can override specific parameters with `DI\autowire()`: +If an object is built using autowiring (with or without attributes), you can override specific parameters with `DI\autowire()`: ```php class Foo diff --git a/doc/definition.md b/doc/definition.md index b40fb97bb..f5413b846 100644 --- a/doc/definition.md +++ b/doc/definition.md @@ -8,7 +8,7 @@ current_menu: definition-introduction To let PHP-DI know what to inject and where, you have several options: - use [autowiring](autowiring.md) -- use [annotations](annotations.md) +- use [attributes](attributes.md) - use [PHP definitions](php-definitions.md) You can also use several or all these options at the same time if you want to. @@ -17,7 +17,7 @@ If you combine several sources, there are priorities that apply. From the highes - Explicit definition on the container (i.e. defined with `$container->set()`) - PHP file definitions (if you add several configuration files, then the last one can override entries from the previous ones) -- Annotations +- PHP attributes - Autowiring Read more in the [Definition overriding documentation](definition-overriding.md) @@ -27,9 +27,9 @@ Read more in the [Definition overriding documentation](definition-overriding.md) See the dedicated documentation about [autowiring](autowiring.md). -## Annotations +## Attributes -See the dedicated documentation about [annotations](annotations.md). +See the dedicated documentation about [attributes](attributes.md). ## PHP configuration diff --git a/doc/frameworks/silex.md b/doc/frameworks/silex.md index a34d95038..81154a4f7 100644 --- a/doc/frameworks/silex.md +++ b/doc/frameworks/silex.md @@ -33,7 +33,7 @@ $app->run(); ## Benefits -Using PHP-DI in Silex allows you to use all the awesome features of PHP-DI to wire your dependencies (using the definition files, autowiring, annotations, …). +Using PHP-DI in Silex allows you to use all the awesome features of PHP-DI to wire your dependencies (using the definition files, autowiring, attributes, …). Another big benefit of the PHP-DI integration is the ability to use dependency injection inside controllers, middlewares and param converters: diff --git a/doc/frameworks/slim.md b/doc/frameworks/slim.md index 5927c89ba..7c7d93eb7 100644 --- a/doc/frameworks/slim.md +++ b/doc/frameworks/slim.md @@ -85,7 +85,7 @@ class UserController $app->delete('/user/{id}', [UserController::class, 'delete']); ``` -Dependencies can then be injected in your controller using [autowiring, PHP-DI config files or even annotations](../definition.md). +Dependencies can then be injected in your controller using [autowiring, PHP-DI config files or even PHP attributes](../definition.md). ### Controller parameters diff --git a/doc/frameworks/symfony2.md b/doc/frameworks/symfony2.md index 76b85741e..74fb3e095 100644 --- a/doc/frameworks/symfony2.md +++ b/doc/frameworks/symfony2.md @@ -76,11 +76,11 @@ class ProductController Example with property injection: ```php +use DI\Attribute\Inject; + class ProductController { - /** - * @Inject - */ + #[Inject] private ProductService $productService; public function clearAction() @@ -148,17 +148,15 @@ services: ### Service name aliases -PHP-DI can also work with autowiring or annotations. These rely on the fact that the service name +PHP-DI can also work with autowiring or PHP attributes. These rely on the fact that the service name is the class name (or interface name), e.g. you reference the entity manager by its class name instead of `doctrine.orm.entity_manager`. -If you want to enjoy autowiring or annotations, you can simplify your life and write simple aliases +If you want to enjoy autowiring or attributes, you can simplify your life and write simple aliases like these: ```php return [ - 'Psr\Log\LoggerInterface' => DI\get('logger'), - // PHP 5.5 notation: ObjectManager::class => DI\get('doctrine.orm.entity_manager'), ]; ``` diff --git a/doc/frameworks/zf1.md b/doc/frameworks/zf1.md index 14205d345..b7ce0bb88 100644 --- a/doc/frameworks/zf1.md +++ b/doc/frameworks/zf1.md @@ -22,7 +22,7 @@ To use PHP-DI in your ZF1 application, you need to change the Dispatcher used by protected function _initContainer() { $builder = new \DI\ContainerBuilder(); - $builder->useAnnotations(true); + $builder->useAttributes(true); $container = $builder->build(); $dispatcher = new \DI\Bridge\ZendFramework1\Dispatcher(); @@ -34,8 +34,6 @@ To use PHP-DI in your ZF1 application, you need to change the Dispatcher used by That's it! -As you can see since PHP-DI 5 it's necessary to enable [annotations](../annotations.md) because they are disabled by default. - **Warning**: if you use Zend's autoloader (and not Composer), you will need to configure it: ```php @@ -53,8 +51,8 @@ class GuestbookController extends Zend_Controller_Action { /** * This dependency will be injected by PHP-DI - * @Inject */ + #[Inject] private Application_Service_GuestbookService $guestbookService; public function indexAction() diff --git a/doc/frameworks/zf2.md b/doc/frameworks/zf2.md index b46fb261c..e8de919ac 100644 --- a/doc/frameworks/zf2.md +++ b/doc/frameworks/zf2.md @@ -35,21 +35,19 @@ Register it in `application_root/config/application.config.php`: That's it! -If you want to use annotations, please read the "Configuration" section below. - ## Usage Now you can inject dependencies in your controllers. -Here is an example of the GuestbookController of the quickstart (using annotations): +Here is an example of the GuestbookController of the quickstart (using attributes): ```php class GuestbookController extends AbstractActionController { /** * This dependency will be injected by PHP-DI - * @Inject */ + #[Inject] private \Application\Service\GuestbookService $guestbookService; public function indexAction() @@ -82,18 +80,6 @@ return [ ]; ``` -### Enable or disable annotations - -Annotations are disabled by default since PHP-DI 5. To enable them, use the following config: - -```php -return [ - 'phpdi-zf2' => [ - 'useAnnotations' => true, - ] -]; -``` - ### Override definitions file location ```php diff --git a/doc/getting-started.md b/doc/getting-started.md index f0e33c082..c974d1b35 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -107,7 +107,7 @@ Don't worry, PHP-DI uses [PHP's Reflection classes](http://php.net/manual/en/boo We have seen **autowiring**, which is when PHP-DI figures out automatically the dependencies a class needs. But we have 3 ways to define what to inject in a class: - using [autowiring](autowiring.md) -- using [annotations](annotations.md) +- using [attributes](attributes.md) - using [PHP definitions](php-definitions.md) Every one of them is different and optional. Here is an example of PHP definitions in a file: @@ -123,7 +123,7 @@ return [ ]; ``` -Please read the [Defining injections](definition.md) documentation to learn about autowiring, annotations and PHP definitions. +Please read the [Defining injections](definition.md) documentation to learn about autowiring, attributes and PHP definitions. ## Framework integration diff --git a/doc/lazy-injection.md b/doc/lazy-injection.md index dea7a9e06..2b63b1fe6 100644 --- a/doc/lazy-injection.md +++ b/doc/lazy-injection.md @@ -102,12 +102,12 @@ return [ ]; ``` -### Annotations +### Attributes ```php -/** - * @Injectable(lazy=true) - */ +use DI\Attribute\Injectable; + +#[Injectable(lazy: true)] class MyClass { } diff --git a/doc/migration/7.0.md b/doc/migration/7.0.md index 59d6cc64d..e45a2f283 100644 --- a/doc/migration/7.0.md +++ b/doc/migration/7.0.md @@ -33,14 +33,22 @@ Related to that: `\DI\ContainerBuilder::buildDevContainer()` method is now obsol + $container = new \DI\Container(); ``` -## PHPdoc types are ignored by `@Inject` +## Annotations (`@Inject`) have been replaced by PHP attributes (`#[Inject]`) -Now that PHP 7.4 and up supports typed properties, PHP-DI will stop reading types from phpdoc. +Now that PHP 8.0 and up [supports attributes natively](https://www.php.net/manual/fr/language.attributes.overview.php), these are read instead of phpdoc annotations. + +Additionally, now that PHP supports typed properties, PHP-DI will stop reading types from phpdoc. Here is an example on how to migrate from PHP-DI 6 to PHP-DI 7: - **before:** +```php +// Container configuration +$containerBuilder = new \DI\ContainerBuilder; +$containerBuilder->useAnnotations(); +``` + ```php class Example { @@ -63,22 +71,28 @@ class Example - **after:** ```php +// Container configuration +$containerBuilder = new \DI\ContainerBuilder; +$containerBuilder->useAttributes(); +``` + +```php +use DI\Attribute\Inject; + class Example { - /** - * @Inject - */ + #[Inject] private Foo $property; - /** - * @Inject - */ + #[Inject] public function method(Foo $param) { } } ``` +Read more about attributes in the PHP-DI documentation: [PHP-DI attributes](../attributes.md). + ## Internal changes If you were overriding or extending some internal classes of PHP-DI, be aware that they may have changed. diff --git a/doc/performances.md b/doc/performances.md index 9167da1c5..3629d8c87 100644 --- a/doc/performances.md +++ b/doc/performances.md @@ -13,7 +13,7 @@ PHP-DI 4 and 5 relied a lot on caching. With PHP-DI 6 the main vector for optimi PHP-DI performs two tasks that can be expensive: -- reading definitions from your [configuration](php-definitions.md), from [autowiring](autowiring.md) or from [annotations](annotations.md) +- reading definitions from your [configuration](php-definitions.md), from [autowiring](autowiring.md) or from [attributes](attributes.md) - resolving those definitions to create your services In order to avoid those two tasks, the container can be compiled into PHP code optimized especially for your configuration and your classes. @@ -43,7 +43,7 @@ If your production handles a lot of traffic you may also want to generate the co ### Development environment -**Do not compile the container in a development environment**, else all the changes you make to the definitions (annotations, configuration files, etc.) will not be taken into account. Here is an example of what you can do: +**Do not compile the container in a development environment**, else all the changes you make to the definitions (attributes, configuration files, etc.) will not be taken into account. Here is an example of what you can do: ```php $containerBuilder = new \DI\ContainerBuilder(); @@ -120,7 +120,7 @@ Compiling the container is the most efficient solution, but it has some limits. - wildcard definitions - usage of `Container::make()` or `Container::injectOn()` (because those are not using the compiled code) -If you make heavy use of those features, and if it slows down your application you can enable the caching system. The cache will ensure annotations or the reflection is not read again on every request. +If you make heavy use of those features, and if it slows down your application you can enable the caching system. The cache will ensure the reflection is not read again on every request. The cache relies on APCu directly because it is the only cache system that makes sense (very fast to write and read). Other caches are not good options, this is why PHP-DI does not use PSR-6 or PSR-16 for this cache. @@ -135,5 +135,5 @@ if (/* is production */) { Heads up: -- do not use a cache in a development environment, else changes you make to the definitions (annotations, configuration files, etc.) may not be taken into account +- do not use a cache in a development environment, else changes you make to the definitions (attributes, configuration files, etc.) may not be taken into account - clear the APCu cache on each deployment in production (to avoid using a stale cache) diff --git a/doc/php-definitions.md b/doc/php-definitions.md index 508100130..864b42162 100644 --- a/doc/php-definitions.md +++ b/doc/php-definitions.md @@ -5,7 +5,7 @@ current_menu: php-definitions # PHP definitions -On top of [autowiring](autowiring.md) and [annotations](annotations.md), you can use **a PHP configuration format** to define injections. +On top of [autowiring](autowiring.md) and [attributes](attributes.md), you can use **a PHP configuration format** to define injections. You can register that configuration as an array: diff --git a/src/Annotation/Inject.php b/src/Annotation/Inject.php deleted file mode 100644 index cc3f7d550..000000000 --- a/src/Annotation/Inject.php +++ /dev/null @@ -1,91 +0,0 @@ - - */ -final class Inject -{ - /** - * Entry name. - */ - private ?string $name = null; - - /** - * Parameters, indexed by the parameter number (index) or name. - * - * Used if the annotation is set on a method - */ - private array $parameters = []; - - /** - * @throws InvalidAnnotation - */ - public function __construct(array $values) - { - // Process the parameters as a list AND as a parameter array (we don't know on what the annotation is) - - // @Inject(name="foo") - if (isset($values['name']) && is_string($values['name'])) { - $this->name = $values['name']; - - return; - } - - // @Inject - if (! isset($values['value'])) { - return; - } - - $values = $values['value']; - - // @Inject("foo") - if (is_string($values)) { - $this->name = $values; - } - - // @Inject({...}) on a method - if (is_array($values)) { - foreach ($values as $key => $value) { - if (! is_string($value)) { - throw new InvalidAnnotation(sprintf( - '@Inject({"param" = "value"}) expects "value" to be a string, %s given.', - json_encode($value) - )); - } - - $this->parameters[$key] = $value; - } - } - } - - /** - * @return string|null Name of the entry to inject - */ - public function getName() : string|null - { - return $this->name; - } - - /** - * @return array Parameters, indexed by the parameter number (index) or name - */ - public function getParameters() : array - { - return $this->parameters; - } -} diff --git a/src/Annotation/Injectable.php b/src/Annotation/Injectable.php deleted file mode 100644 index ddab369bc..000000000 --- a/src/Annotation/Injectable.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @author Matthieu Napoli - */ -final class Injectable -{ - /** - * Should the object be lazy-loaded. - */ - private ?bool $lazy = null; - - public function __construct(array $values) - { - if (isset($values['lazy'])) { - $this->lazy = (bool) $values['lazy']; - } - } - - public function isLazy() : bool|null - { - return $this->lazy; - } -} diff --git a/src/Attribute/Inject.php b/src/Attribute/Inject.php index 988cb738e..34339d2df 100644 --- a/src/Attribute/Inject.php +++ b/src/Attribute/Inject.php @@ -5,7 +5,7 @@ namespace DI\Attribute; use Attribute; -use DI\Definition\Exception\InvalidAnnotation; +use DI\Definition\Exception\InvalidAttribute; /** * #[Inject] attribute. @@ -27,12 +27,12 @@ final class Inject /** * Parameters, indexed by the parameter number (index) or name. * - * Used if the annotation is set on a method + * Used if the attribute is set on a method */ private array $parameters = []; /** - * @throws InvalidAnnotation + * @throws InvalidAttribute */ public function __construct(string|array|null $name = null) { @@ -45,7 +45,7 @@ public function __construct(string|array|null $name = null) if (is_array($name)) { foreach ($name as $key => $value) { if (! is_string($value)) { - throw new InvalidAnnotation(sprintf( + throw new InvalidAttribute(sprintf( "#[Inject(['param' => 'value'])] expects \"value\" to be a string, %s given.", json_encode($value, \JSON_THROW_ON_ERROR) )); diff --git a/src/Attribute/Injectable.php b/src/Attribute/Injectable.php index 2acb78326..86dfdd4b4 100644 --- a/src/Attribute/Injectable.php +++ b/src/Attribute/Injectable.php @@ -7,7 +7,7 @@ use Attribute; /** - * "Injectable" annotation. + * "Injectable" attribute. * * Marks a class as injectable * diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index f27f6736d..a582e3714 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -5,7 +5,6 @@ namespace DI; use DI\Compiler\Compiler; -use DI\Definition\Source\AnnotationBasedAutowiring; use DI\Definition\Source\AttributeBasedAutowiring; use DI\Definition\Source\DefinitionArray; use DI\Definition\Source\DefinitionFile; @@ -49,8 +48,6 @@ class ContainerBuilder private bool $useAutowiring = true; - private bool $useAnnotations = false; - private bool $useAttributes = false; /** @@ -100,9 +97,6 @@ public function build() if ($this->useAttributes) { $autowiring = new AttributeBasedAutowiring; $sources[] = $autowiring; - } elseif ($this->useAnnotations) { - $autowiring = new AnnotationBasedAutowiring; - $sources[] = $autowiring; } elseif ($this->useAutowiring) { $autowiring = new ReflectionBasedAutowiring; $sources[] = $autowiring; @@ -147,7 +141,7 @@ public function build() $this->compileToDirectory, $containerClass, $this->containerParentClass, - $this->useAutowiring || $this->useAnnotations + $this->useAutowiring ); // Only load the file if it hasn't been already loaded // (the container can be created multiple times in the same process) @@ -207,22 +201,6 @@ public function useAutowiring(bool $bool) : self return $this; } - /** - * Enable or disable the use of annotations to guess injections. - * - * Disabled by default. - * - * @return $this - */ - public function useAnnotations(bool $bool) : self - { - $this->ensureNotLocked(); - - $this->useAnnotations = $bool; - - return $this; - } - /** * Enable or disable the use of PHP 8 attributes to configure injections. * @@ -307,7 +285,7 @@ public function addDefinitions(string|array|DefinitionSource ...$definitions) : * * Before using this feature, you should try these steps first: * - enable compilation if not already done (see `enableCompilation()`) - * - if you use autowiring or annotations, add all the classes you are using into your configuration so that + * - if you use autowiring or attributes, add all the classes you are using into your configuration so that * PHP-DI knows about them and compiles them * Once this is done, you can try to optimize performances further with APCu. It can also be useful if you use * `Container::make()` instead of `get()` (`make()` calls cannot be compiled so they are not optimized). diff --git a/src/Definition/Exception/InvalidAnnotation.php b/src/Definition/Exception/InvalidAttribute.php similarity index 57% rename from src/Definition/Exception/InvalidAnnotation.php rename to src/Definition/Exception/InvalidAttribute.php index 630c34a08..4504f18ab 100644 --- a/src/Definition/Exception/InvalidAnnotation.php +++ b/src/Definition/Exception/InvalidAttribute.php @@ -5,10 +5,10 @@ namespace DI\Definition\Exception; /** - * Error in the definitions using annotations. + * Error in the definitions using PHP attributes. * * @author Matthieu Napoli */ -class InvalidAnnotation extends InvalidDefinition +class InvalidAttribute extends InvalidDefinition { } diff --git a/src/Definition/Helper/AutowireDefinitionHelper.php b/src/Definition/Helper/AutowireDefinitionHelper.php index 7d548672c..01b59e8fe 100644 --- a/src/Definition/Helper/AutowireDefinitionHelper.php +++ b/src/Definition/Helper/AutowireDefinitionHelper.php @@ -18,9 +18,9 @@ class AutowireDefinitionHelper extends CreateDefinitionHelper /** * Defines a value for a specific argument of the constructor. * - * This method is usually used together with annotations or autowiring, when a parameter + * This method is usually used together with attributes or autowiring, when a parameter * is not (or cannot be) type-hinted. Using this method instead of constructor() allows to - * avoid defining all the parameters (letting them being resolved using annotations or autowiring) + * avoid defining all the parameters (letting them being resolved using attributes or autowiring) * and only define one. * * @param string|int $parameter Parameter name of position for which the value will be given. @@ -38,9 +38,9 @@ public function constructorParameter(string|int $parameter, mixed $value) : self /** * Defines a method to call and a value for a specific argument. * - * This method is usually used together with annotations or autowiring, when a parameter + * This method is usually used together with attributes or autowiring, when a parameter * is not (or cannot be) type-hinted. Using this method instead of method() allows to - * avoid defining all the parameters (letting them being resolved using annotations or + * avoid defining all the parameters (letting them being resolved using attributes or * autowiring) and only define one. * * If multiple calls to the method have been configured already (e.g. in a previous definition) diff --git a/src/Definition/Helper/FactoryDefinitionHelper.php b/src/Definition/Helper/FactoryDefinitionHelper.php index a6906c85a..85e1ba525 100644 --- a/src/Definition/Helper/FactoryDefinitionHelper.php +++ b/src/Definition/Helper/FactoryDefinitionHelper.php @@ -44,7 +44,7 @@ public function getDefinition(string $entryName) : FactoryDefinition /** * Defines arguments to pass to the factory. * - * Because factory methods do not yet support annotations or autowiring, this method + * Because factory methods do not yet support attributes or autowiring, this method * should be used to define all parameters except the ContainerInterface and RequestedEntry. * * Multiple calls can be made to the method to override individual values. diff --git a/src/Definition/Source/AnnotationBasedAutowiring.php b/src/Definition/Source/AnnotationBasedAutowiring.php deleted file mode 100644 index 1d01c4d84..000000000 --- a/src/Definition/Source/AnnotationBasedAutowiring.php +++ /dev/null @@ -1,273 +0,0 @@ - - */ -class AnnotationBasedAutowiring implements DefinitionSource, Autowiring -{ - private ?Reader $annotationReader = null; - - /** - * @throws InvalidAnnotation - */ - public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition|null - { - $className = $definition ? $definition->getClassName() : $name; - - if (!class_exists($className) && !interface_exists($className)) { - return $definition; - } - - $definition = $definition ?: new ObjectDefinition($name); - - $class = new ReflectionClass($className); - - $this->readInjectableAnnotation($class, $definition); - - // Browse the class properties looking for annotated properties - $this->readProperties($class, $definition); - - // Browse the object's methods looking for annotated methods - $this->readMethods($class, $definition); - - return $definition; - } - - /** - * {@inheritdoc} - * @throws InvalidAnnotation - * @throws InvalidArgumentException The class doesn't exist - */ - public function getDefinition(string $name) : ObjectDefinition|null - { - return $this->autowire($name); - } - - /** - * Autowiring cannot guess all existing definitions. - */ - public function getDefinitions() : array - { - return []; - } - - /** - * Browse the class properties looking for annotated properties. - */ - private function readProperties(ReflectionClass $class, ObjectDefinition $definition) : void - { - foreach ($class->getProperties() as $property) { - if ($property->isStatic()) { - continue; - } - $this->readProperty($property, $definition); - } - - // Read also the *private* properties of the parent classes - /** @noinspection PhpAssignmentInConditionInspection */ - while ($class = $class->getParentClass()) { - foreach ($class->getProperties(ReflectionProperty::IS_PRIVATE) as $property) { - if ($property->isStatic()) { - continue; - } - $this->readProperty($property, $definition, $class->getName()); - } - } - } - - /** - * @throws InvalidAnnotation - */ - private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, ?string $classname = null) : void - { - // Look for @Inject annotation - $annotation = $this->getAnnotationReader()->getPropertyAnnotation($property, Inject::class); - if (!$annotation instanceof Inject) { - return; - } - - // Try to @Inject("name") or look for the property type - $entryName = $annotation->getName(); - - // Try using typed properties - $propertyType = $property->getType(); - if ($entryName === null && $propertyType instanceof ReflectionNamedType) { - if (! class_exists($propertyType->getName()) && ! interface_exists($propertyType->getName())) { - throw new InvalidAnnotation(sprintf( - '@Inject found on property %s::%s but unable to guess what to inject, the type of the property does not look like a valid class or interface name', - $property->getDeclaringClass()->getName(), - $property->getName() - )); - } - $entryName = $propertyType->getName(); - } - - if ($entryName === null) { - throw new InvalidAnnotation(sprintf( - '@Inject found on property %s::%s but unable to guess what to inject, please add a type to the property', - $property->getDeclaringClass()->getName(), - $property->getName() - )); - } - - $definition->addPropertyInjection( - new PropertyInjection($property->getName(), new Reference($entryName), $classname) - ); - } - - /** - * Browse the object's methods looking for annotated methods. - */ - private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition) : void - { - // This will look in all the methods, including those of the parent classes - foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { - if ($method->isStatic()) { - continue; - } - - $methodInjection = $this->getMethodInjection($method); - - if (! $methodInjection) { - continue; - } - - if ($method->isConstructor()) { - $objectDefinition->completeConstructorInjection($methodInjection); - } else { - $objectDefinition->completeFirstMethodInjection($methodInjection); - } - } - } - - /** - * @throws InvalidAnnotation - */ - private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection - { - // Look for @Inject annotation - try { - $annotation = $this->getAnnotationReader()->getMethodAnnotation($method, Inject::class); - } catch (InvalidAnnotation $e) { - throw new InvalidAnnotation(sprintf( - '@Inject annotation on %s::%s is malformed. %s', - $method->getDeclaringClass()->getName(), - $method->getName(), - $e->getMessage() - ), 0, $e); - } - - // @Inject on constructor is implicit - if (! ($annotation || $method->isConstructor())) { - return null; - } - - $annotationParameters = $annotation instanceof Inject ? $annotation->getParameters() : []; - - $parameters = []; - foreach ($method->getParameters() as $index => $parameter) { - $entryName = $this->getMethodParameter($index, $parameter, $annotationParameters); - - if ($entryName !== null) { - $parameters[$index] = new Reference($entryName); - } - } - - if ($method->isConstructor()) { - return MethodInjection::constructor($parameters); - } - - return new MethodInjection($method->getName(), $parameters); - } - - /** - * @return string|null Entry name or null if not found. - */ - private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters) : string|null - { - // @Inject has definition for this parameter (by index, or by name) - if (isset($annotationParameters[$parameterIndex])) { - return $annotationParameters[$parameterIndex]; - } - if (isset($annotationParameters[$parameter->getName()])) { - return $annotationParameters[$parameter->getName()]; - } - - // Skip optional parameters if not explicitly defined - if ($parameter->isOptional()) { - return null; - } - - // Look for the property type - $parameterType = $parameter->getType(); - if ($parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) { - return $parameterType->getName(); - } - - return null; - } - - public function getAnnotationReader() : Reader - { - if ($this->annotationReader === null) { - AnnotationRegistry::registerLoader('class_exists'); - $this->annotationReader = new SimpleAnnotationReader(); - $this->annotationReader->addNamespace('DI\Annotation'); - } - - return $this->annotationReader; - } - - /** - * @throws InvalidAnnotation - */ - private function readInjectableAnnotation(ReflectionClass $class, ObjectDefinition $definition) : void - { - try { - /** @var Injectable|null $annotation */ - $annotation = $this->getAnnotationReader() - ->getClassAnnotation($class, Injectable::class); - } catch (UnexpectedValueException $e) { - throw new InvalidAnnotation(sprintf( - 'Error while reading @Injectable on %s: %s', - $class->getName(), - $e->getMessage() - ), 0, $e); - } - - if (! $annotation) { - return; - } - - if ($annotation->isLazy() !== null) { - $definition->setLazy($annotation->isLazy()); - } - } -} diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php index b72d72d75..709759816 100644 --- a/src/Definition/Source/AttributeBasedAutowiring.php +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -6,7 +6,7 @@ use DI\Attribute\Inject; use DI\Attribute\Injectable; -use DI\Definition\Exception\InvalidAnnotation; +use DI\Definition\Exception\InvalidAttribute; use DI\Definition\ObjectDefinition; use DI\Definition\ObjectDefinition\MethodInjection; use DI\Definition\ObjectDefinition\PropertyInjection; @@ -28,15 +28,8 @@ */ class AttributeBasedAutowiring implements DefinitionSource, Autowiring { - public function __construct() - { - if (\PHP_VERSION_ID < 80000) { - throw new \Exception('Using PHP 8 attributes for autowiring is only supported with PHP 8'); - } - } - /** - * @throws InvalidAnnotation + * @throws InvalidAttribute */ public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition|null { @@ -63,7 +56,7 @@ public function autowire(string $name, ObjectDefinition $definition = null) : Ob /** * {@inheritdoc} - * @throws InvalidAnnotation + * @throws InvalidAttribute * @throws InvalidArgumentException The class doesn't exist */ public function getDefinition(string $name) : ObjectDefinition|null @@ -104,11 +97,11 @@ private function readProperties(ReflectionClass $class, ObjectDefinition $defini } /** - * @throws InvalidAnnotation + * @throws InvalidAttribute */ private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, ?string $classname = null) : void { - // Look for #[Inject] annotation + // Look for #[Inject] attribute try { $attribute = $property->getAttributes(Inject::class)[0] ?? null; if (! $attribute) { @@ -117,7 +110,7 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de /** @var Inject $inject */ $inject = $attribute->newInstance(); } catch (Throwable $e) { - throw new InvalidAnnotation(sprintf( + throw new InvalidAttribute(sprintf( '#[Inject] annotation on property %s::%s is malformed. %s', $property->getDeclaringClass()->getName(), $property->getName(), @@ -132,7 +125,7 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de $propertyType = $property->getType(); if ($entryName === null && $propertyType instanceof ReflectionNamedType) { if (! class_exists($propertyType->getName()) && ! interface_exists($propertyType->getName())) { - throw new InvalidAnnotation(sprintf( + throw new InvalidAttribute(sprintf( '#[Inject] found on property %s::%s but unable to guess what to inject, the type of the property does not look like a valid class or interface name', $property->getDeclaringClass()->getName(), $property->getName() @@ -142,7 +135,7 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de } if ($entryName === null) { - throw new InvalidAnnotation(sprintf( + throw new InvalidAttribute(sprintf( '#[Inject] found on property %s::%s but unable to guess what to inject, please add a type to the property', $property->getDeclaringClass()->getName(), $property->getName() @@ -248,7 +241,7 @@ private function getMethodParameter(int $parameterIndex, ReflectionParameter $pa } /** - * @throws InvalidAnnotation + * @throws InvalidAttribute */ private function readInjectableAttribute(ReflectionClass $class, ObjectDefinition $definition) : void { @@ -259,7 +252,7 @@ private function readInjectableAttribute(ReflectionClass $class, ObjectDefinitio } $attribute = $attribute->newInstance(); } catch (Throwable $e) { - throw new InvalidAnnotation(sprintf( + throw new InvalidAttribute(sprintf( 'Error while reading #[Injectable] on %s: %s', $class->getName(), $e->getMessage() diff --git a/tests/IntegrationTest/Annotations/A.php b/tests/IntegrationTest/Annotations/A.php deleted file mode 100644 index d5129f243..000000000 --- a/tests/IntegrationTest/Annotations/A.php +++ /dev/null @@ -1,9 +0,0 @@ -useAnnotations(true); - - /** @var B $object */ - $object = $builder->build()->get(B::class); - - $this->assertInstanceOf(A::class, $object->public); - $this->assertInstanceOf(A::class, $object->getProtected()); - $this->assertInstanceOf(A::class, $object->getPrivate()); - } - - /** - * Inject in parent properties (public, protected and private). - * - * @test - * @dataProvider provideContainer - */ - public function inject_in_parent_properties(ContainerBuilder $builder) - { - $builder->useAnnotations(true); - $container = $builder->build(); - - /** @var C $object */ - $object = $container->get(C::class); - $this->assertInstanceOf(A::class, $object->public); - $this->assertInstanceOf(A::class, $object->getProtected()); - $this->assertInstanceOf(A::class, $object->getPrivate()); - - /** @var D $object */ - $object = $container->get(D::class); - $this->assertInstanceOf(A::class, $object->public); - $this->assertInstanceOf(A::class, $object->getProtected()); - $this->assertInstanceOf(A::class, $object->getPrivate()); - } - - /** - * Inject in private parent properties even if they have the same name of child properties. - * - * @test - * @dataProvider provideContainer - */ - public function inject_in_private_parent_properties_with_same_name(ContainerBuilder $builder) - { - $builder->useAnnotations(true); - $container = $builder->build(); - - /** @var Child $object */ - $object = $container->get(Child::class); - $this->assertInstanceOf(A::class, $object->public); - $this->assertInstanceOf(A::class, $object->getProtected()); - $this->assertInstanceOf(A::class, $object->getPrivate()); - $this->assertInstanceOf(A::class, $object->getChildPrivate()); - } - - /** - * @test - * @dataProvider provideContainer - */ - public function inject_by_name(ContainerBuilder $builder) - { - $builder->useAnnotations(true); - - $dependency = new \stdClass(); - - $builder->addDefinitions([ - 'namedDependency' => $dependency, - ]); - $container = $builder->build(); - - /** @var NamedInjection $object */ - $object = $container->get(NamedInjection::class); - $this->assertSame($dependency, $object->dependency); - } - - /** - * @test - * @dataProvider provideContainer - */ - public function errors_if_dependency_by_name_not_found(ContainerBuilder $builder) - { - $this->expectException(DependencyException::class); - $builder->useAnnotations(true); - $builder->build()->get(NamedInjection::class); - } -} diff --git a/tests/IntegrationTest/Annotations/B.php b/tests/IntegrationTest/Annotations/B.php deleted file mode 100644 index 05aa88694..000000000 --- a/tests/IntegrationTest/Annotations/B.php +++ /dev/null @@ -1,35 +0,0 @@ -protected; - } - - public function getPrivate() - { - return $this->private; - } -} diff --git a/tests/IntegrationTest/Annotations/C.php b/tests/IntegrationTest/Annotations/C.php deleted file mode 100644 index 031b98284..000000000 --- a/tests/IntegrationTest/Annotations/C.php +++ /dev/null @@ -1,9 +0,0 @@ -private; - } -} diff --git a/tests/IntegrationTest/Annotations/D.php b/tests/IntegrationTest/Annotations/D.php deleted file mode 100644 index 046027951..000000000 --- a/tests/IntegrationTest/Annotations/D.php +++ /dev/null @@ -1,9 +0,0 @@ -expectException(DependencyException::class); $this->expectExceptionMessage('Circular dependency detected while trying to resolve entry \'DI\Test\UnitTest\Fixtures\Class1CircularDependencies\''); - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->build()->get(Class1CircularDependencies::class); } diff --git a/tests/IntegrationTest/ContainerInjectOnTest.php b/tests/IntegrationTest/ContainerInjectOnTest.php index e2500fa1f..b5bac0e91 100644 --- a/tests/IntegrationTest/ContainerInjectOnTest.php +++ b/tests/IntegrationTest/ContainerInjectOnTest.php @@ -4,6 +4,7 @@ namespace DI\Test\IntegrationTest; +use DI\Attribute\Inject; use DI\ContainerBuilder; use DI\Test\IntegrationTest\Fixtures\Class1; use DI\Test\IntegrationTest\Fixtures\Class2; @@ -33,10 +34,10 @@ public function test_returns_the_same_object(ContainerBuilder $builder) /** * @dataProvider provideContainer */ - public function test_inject_on_object_using_annotations(ContainerBuilder $builder) + public function test_inject_on_object_using_attributes(ContainerBuilder $builder) { $builder->useAutowiring(true); - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->addDefinitions([ 'foo' => 'bar', Interface1::class => create(Implementation1::class), @@ -66,7 +67,7 @@ public function test_inject_on_object_using_annotations(ContainerBuilder $builde self::assertInstanceOf(Class2::class, $obj->method1Param1); // Method 2 (automatic resolution with type hinting) self::assertInstanceOf(Implementation1::class, $obj->method2Param1); - // Method 3 (defining parameters with the annotation) + // Method 3 (defining parameters with the attribute) self::assertInstanceOf(Class2::class, $obj->method3Param1); self::assertEquals('bar', $obj->method3Param2); // Method 4 (lazy) @@ -84,7 +85,7 @@ public function test_inject_on_object_using_annotations(ContainerBuilder $builde public function test_inject_on_object_using_config(ContainerBuilder $builder) { $builder->useAutowiring(false); - $builder->useAnnotations(false); + $builder->useAttributes(false); $builder->addDefinitions([ 'foo' => 'bar', @@ -136,7 +137,7 @@ public function test_inject_on_object_using_config(ContainerBuilder $builder) self::assertInstanceOf(Class2::class, $obj->method1Param1); // Method 2 (automatic resolution with type hinting) self::assertInstanceOf(Implementation1::class, $obj->method2Param1); - // Method 3 (defining parameters with the annotation) + // Method 3 (defining parameters with the attribute) self::assertInstanceOf(Class2::class, $obj->method3Param1); self::assertEquals('bar', $obj->method3Param2); // Method 4 (lazy) @@ -154,23 +155,19 @@ public function test_inject_on_object_using_config(ContainerBuilder $builder) public function testInjectOnAnonClass(ContainerBuilder $builder) { $obj = new class { - /** - * @Inject - */ + #[Inject] public Class2 $property; public $methodParam; - /** - * @Inject - */ + #[Inject] public function setParam(Class2 $param) { $this->methodParam = $param; } }; - $builder->useAnnotations(true); + $builder->useAttributes(true); $container = $builder->build(); $container->injectOn($obj); diff --git a/tests/IntegrationTest/ContainerMakeTest.php b/tests/IntegrationTest/ContainerMakeTest.php index 1e9a9563f..65b0ee7bd 100644 --- a/tests/IntegrationTest/ContainerMakeTest.php +++ b/tests/IntegrationTest/ContainerMakeTest.php @@ -72,7 +72,7 @@ public function testCircularDependencyException(ContainerBuilder $builder) { $this->expectException(DependencyException::class); $this->expectExceptionMessage('Circular dependency detected while trying to resolve entry \'DI\Test\UnitTest\Fixtures\Class1CircularDependencies\''); - $builder->useAnnotations(true); + $builder->useAttributes(true); $container = $builder->build(); $container->make(Class1CircularDependencies::class); } diff --git a/tests/IntegrationTest/Definitions/AnnotationTest.php b/tests/IntegrationTest/Definitions/AnnotationTest.php deleted file mode 100644 index 9b1143c27..000000000 --- a/tests/IntegrationTest/Definitions/AnnotationTest.php +++ /dev/null @@ -1,189 +0,0 @@ -useAnnotations(true)->build(); - self::assertInstanceOf(NonAnnotatedClass::class, $container->get(NonAnnotatedClass::class)); - } - - /** - * @dataProvider provideContainer - */ - public function test_constructor_injection(ContainerBuilder $builder) - { - $builder->useAnnotations(true); - $builder->addDefinitions([ - 'foo' => 'bar', - 'lazyService' => autowire(\stdClass::class)->lazy(), - ]); - $container = $builder->build(); - - $object = $container->get(ConstructorInjection::class); - - self::assertEquals(new \stdClass, $object->typedValue); - self::assertEquals(new \stdClass, $object->typedOptionalValue); - self::assertEquals('bar', $object->value); - self::assertInstanceOf(\stdClass::class, $object->lazyService); - self::assertInstanceOf(LazyLoadingInterface::class, $object->lazyService); - self::assertFalse($object->lazyService->isProxyInitialized()); - self::assertEquals('hello', $object->optionalValue); - } - - /** - * @dataProvider provideContainer - */ - public function test_property_injection(ContainerBuilder $builder) - { - $builder->useAnnotations(true); - $builder->addDefinitions([ - 'foo' => 'bar', - 'lazyService' => autowire(\stdClass::class)->lazy(), - ]); - $container = $builder->build(); - - $object = $container->get(PropertyInjection::class); - - self::assertEquals('bar', $object->value); - self::assertEquals('bar', $object->value2); - self::assertInstanceOf(\stdClass::class, $object->entry); - self::assertInstanceOf(\stdClass::class, $object->lazyService); - self::assertInstanceOf(LazyLoadingInterface::class, $object->lazyService); - self::assertFalse($object->lazyService->isProxyInitialized()); - } - - /** - * @dataProvider provideContainer - */ - public function test_method_injection(ContainerBuilder $builder) - { - $builder->useAnnotations(true); - $builder->addDefinitions([ - 'foo' => 'bar', - 'lazyService' => autowire(\stdClass::class)->lazy(), - ]); - $container = $builder->build(); - - $object = $container->get(ConstructorInjection::class); - - self::assertEquals(new \stdClass, $object->typedValue); - self::assertEquals(new \stdClass, $object->typedOptionalValue); - self::assertEquals('bar', $object->value); - self::assertInstanceOf(\stdClass::class, $object->lazyService); - self::assertInstanceOf(LazyLoadingInterface::class, $object->lazyService); - self::assertFalse($object->lazyService->isProxyInitialized()); - self::assertEquals('hello', $object->optionalValue); - } -} - -namespace DI\Test\IntegrationTest\Definitions\AnnotationTest; - -use DI\Annotation\Inject; -use stdClass; - -class NonAnnotatedClass -{ -} - -class NamespacedClass -{ -} - -class ConstructorInjection -{ - public $value; - public $scalarValue; - public $typedValue; - public $typedOptionalValue; - /** @var \ProxyManager\Proxy\LazyLoadingInterface */ - public $lazyService; - public $optionalValue; - - /** - * @Inject({"value" = "foo", "scalarValue" = "foo", "lazyService" = "lazyService"}) - */ - public function __construct( - $value, - string $scalarValue, - \stdClass $typedValue, - \stdClass $typedOptionalValue = null, - \stdClass $lazyService, - $optionalValue = 'hello' - ) { - $this->value = $value; - $this->scalarValue = $scalarValue; - $this->typedValue = $typedValue; - $this->typedOptionalValue = $typedOptionalValue; - $this->lazyService = $lazyService; - $this->optionalValue = $optionalValue; - } -} - -class PropertyInjection -{ - /** - * @Inject(name="foo") - */ - public $value; - /** - * @Inject("foo") - */ - public $value2; - /** - * @Inject - */ - public stdClass $entry; - /** - * @Inject("lazyService") - */ - public $lazyService; -} - -class MethodInjection -{ - public $value; - public $scalarValue; - public $typedValue; - public $typedOptionalValue; - /** @var \ProxyManager\Proxy\LazyLoadingInterface */ - public $lazyService; - public $optionalValue; - - /** - * @Inject({"value" = "foo", "scalarValue" = "foo", "lazyService" = "lazyService"}) - */ - public function method( - $value, - string $scalarValue, - $untypedValue, - \stdClass $typedOptionalValue = null, - \stdClass $lazyService, - $optionalValue = 'hello' - ) { - $this->value = $value; - $this->scalarValue = $scalarValue; - $this->untypedValue = $untypedValue; - $this->typedOptionalValue = $typedOptionalValue; - $this->lazyService = $lazyService; - $this->optionalValue = $optionalValue; - } -} diff --git a/tests/IntegrationTest/Definitions/AutowireDefinition/ConstructorInjection.php b/tests/IntegrationTest/Definitions/AutowireDefinition/ConstructorInjection.php index 1fe6e0e51..ddc0f751c 100644 --- a/tests/IntegrationTest/Definitions/AutowireDefinition/ConstructorInjection.php +++ b/tests/IntegrationTest/Definitions/AutowireDefinition/ConstructorInjection.php @@ -4,7 +4,7 @@ namespace DI\Test\IntegrationTest\Definitions\AutowireDefinition; -use DI\Annotation\Inject; +use DI\Attribute\Inject; class ConstructorInjection { @@ -19,9 +19,9 @@ class ConstructorInjection public $overloadedParameter; /** - * Force the injection of a specific value for the first parameter. (when using annotations). - * @Inject({"autowiredParameter"="anotherStdClass"}) + * Force the injection of a specific value for the first parameter. (when using attributes). */ + #[Inject(['autowiredParameter' => 'anotherStdClass'])] public function __construct(\stdClass $autowiredParameter, Class1 $overloadedParameter) { $this->autowiredParameter = $autowiredParameter; diff --git a/tests/IntegrationTest/Definitions/AutowireDefinition/MethodInjection.php b/tests/IntegrationTest/Definitions/AutowireDefinition/MethodInjection.php index 3d7e3b0a4..394ad3b67 100644 --- a/tests/IntegrationTest/Definitions/AutowireDefinition/MethodInjection.php +++ b/tests/IntegrationTest/Definitions/AutowireDefinition/MethodInjection.php @@ -4,7 +4,7 @@ namespace DI\Test\IntegrationTest\Definitions\AutowireDefinition; -use DI\Annotation\Inject; +use DI\Attribute\Inject; class MethodInjection { @@ -19,9 +19,9 @@ class MethodInjection public $overloadedParameter; /** - * Force the injection of a specific value for the first parameter. (when using annotations). - * @Inject({"autowiredParameter"="anotherStdClass"}) + * Force the injection of a specific value for the first parameter (when using attributes). */ + #[Inject(['autowiredParameter' => 'anotherStdClass'])] public function setFoo(\stdClass $autowiredParameter, Class1 $overloadedParameter) { $this->autowiredParameter = $autowiredParameter; diff --git a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php index 6f35f58bc..d93c4a6db 100644 --- a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php @@ -112,7 +112,7 @@ public function test_autowired_constructor_injection_can_be_overloaded(Container */ public function test_annotated_constructor_injection_can_be_overloaded(ContainerBuilder $builder) { - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->addDefinitions([ AutowireDefinition\ConstructorInjection::class => autowire() ->constructorParameter('overloadedParameter', get('foo')), @@ -139,7 +139,7 @@ public function test_annotated_constructor_injection_can_be_overloaded(Container */ public function test_annotated_method_injection_can_be_overloaded(ContainerBuilder $builder) { - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->addDefinitions([ AutowireDefinition\MethodInjection::class => autowire() ->methodParameter('setFoo', 'overloadedParameter', get('foo')), diff --git a/tests/IntegrationTest/Definitions/WildcardDefinitionsTest.php b/tests/IntegrationTest/Definitions/WildcardDefinitionsTest.php index 5685282f6..935213123 100644 --- a/tests/IntegrationTest/Definitions/WildcardDefinitionsTest.php +++ b/tests/IntegrationTest/Definitions/WildcardDefinitionsTest.php @@ -4,7 +4,7 @@ namespace DI\Test\IntegrationTest\Definitions; -use DI\Annotation\Inject; +use DI\Attribute\Inject; use DI\ContainerBuilder; use DI\Test\IntegrationTest\BaseContainerTest; use DI\Test\IntegrationTest\Fixtures\Implementation1; @@ -99,7 +99,7 @@ public function test_wildcards_autowire_with_dependency(ContainerBuilder $builde */ public function test_wildcards_as_dependency(ContainerBuilder $builder) { - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->addDefinitions([ 'DI\Test\IntegrationTest\*\Interface*' => \DI\create('DI\Test\IntegrationTest\*\Implementation*'), ]); @@ -113,8 +113,6 @@ public function test_wildcards_as_dependency(ContainerBuilder $builder) class WildcardDefinitionsTestFixture { - /** - * @Inject - */ + #[Inject] public Interface1 $dependency; } diff --git a/tests/IntegrationTest/ErrorMessages/Buggy2.php b/tests/IntegrationTest/ErrorMessages/Buggy2.php index c1aaf1d72..7003ca33d 100644 --- a/tests/IntegrationTest/ErrorMessages/Buggy2.php +++ b/tests/IntegrationTest/ErrorMessages/Buggy2.php @@ -4,14 +4,11 @@ namespace DI\Test\IntegrationTest\ErrorMessages; -use DI\Annotation\Inject; +use DI\Attribute\Inject; class Buggy2 { - /** - * @Inject({"nonExistentEntry"}) - * @param $dependency - */ + #[Inject(['nonExistentEntry'])] public function __construct($dependency) { } diff --git a/tests/IntegrationTest/ErrorMessages/Buggy3.php b/tests/IntegrationTest/ErrorMessages/Buggy3.php index dbf8e8989..c2d2f9e67 100644 --- a/tests/IntegrationTest/ErrorMessages/Buggy3.php +++ b/tests/IntegrationTest/ErrorMessages/Buggy3.php @@ -4,12 +4,10 @@ namespace DI\Test\IntegrationTest\ErrorMessages; -use DI\Annotation\Inject; +use DI\Attribute\Inject; class Buggy3 { - /** - * @Inject(name="namedDependency") - */ + #[Inject(name: 'namedDependency')] public $dependency; } diff --git a/tests/IntegrationTest/ErrorMessages/Buggy4.php b/tests/IntegrationTest/ErrorMessages/Buggy4.php index e0c992652..4c601600b 100644 --- a/tests/IntegrationTest/ErrorMessages/Buggy4.php +++ b/tests/IntegrationTest/ErrorMessages/Buggy4.php @@ -4,13 +4,11 @@ namespace DI\Test\IntegrationTest\ErrorMessages; -use DI\Annotation\Inject; +use DI\Attribute\Inject; class Buggy4 { - /** - * @Inject({"nonExistentBean"}) - */ + #[Inject(['nonExistentBean'])] public function setDependency($dependency) { } diff --git a/tests/IntegrationTest/ErrorMessages/Buggy5.php b/tests/IntegrationTest/ErrorMessages/Buggy5.php index 9ab77cb91..f6ed30258 100644 --- a/tests/IntegrationTest/ErrorMessages/Buggy5.php +++ b/tests/IntegrationTest/ErrorMessages/Buggy5.php @@ -4,13 +4,11 @@ namespace DI\Test\IntegrationTest\ErrorMessages; -use DI\Annotation\Inject; +use DI\Attribute\Inject; class Buggy5 { - /** - * @Inject - */ + #[Inject] public function setDependency($dependency) { $this->dependency = $dependency; diff --git a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php index c21ca4462..da3dd4157 100644 --- a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php +++ b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php @@ -99,7 +99,7 @@ public function test_constructor_injection_of_non_existent_container_entry(Conta { $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while injecting dependencies into DI\Test\IntegrationTest\ErrorMessages\Buggy2: No entry or class found for \'nonExistentEntry\''); - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->build()->get(Buggy2::class); } @@ -110,7 +110,7 @@ public function test_property_injection_of_non_existent_container_entry(Containe { $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while injecting in DI\Test\IntegrationTest\ErrorMessages\Buggy3::dependency. No entry or class found for \'namedDependency\''); - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->build()->get(Buggy3::class); } @@ -119,9 +119,9 @@ public function test_property_injection_of_non_existent_container_entry(Containe */ public function test_setter_injection_of_non_existent_container_entry(ContainerBuilder $builder) { - $this->expectException(DependencyException::class); $this->expectExceptionMessage('Error while injecting dependencies into DI\Test\IntegrationTest\ErrorMessages\Buggy4: No entry or class found for \'nonExistentBean\''); - $builder->useAnnotations(true); + $this->expectException(DependencyException::class); + $builder->useAttributes(true); $builder->build()->get(Buggy4::class); } @@ -145,7 +145,7 @@ class = DI\Test\IntegrationTest\ErrorMessages\Buggy5 $this->expectException(InvalidDefinition::class); $this->expectExceptionMessage($message); - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->addDefinitions([ Buggy5::class => autowire(), ]); diff --git a/tests/IntegrationTest/Fixtures/Class1.php b/tests/IntegrationTest/Fixtures/Class1.php index b72b2ebae..3014bd541 100644 --- a/tests/IntegrationTest/Fixtures/Class1.php +++ b/tests/IntegrationTest/Fixtures/Class1.php @@ -4,38 +4,28 @@ namespace DI\Test\IntegrationTest\Fixtures; -use DI\Annotation\Inject; -use DI\Annotation\Injectable; +use DI\Attribute\Inject; +use DI\Attribute\Injectable; /** * Fixture class. - * @Injectable */ +#[Injectable] class Class1 { - /** - * @Inject - */ + #[Inject] public Class2 $property1; - /** - * @Inject - */ + #[Inject] public Interface1 $property2; - /** - * @Inject("namedDependency") - */ + #[Inject('namedDependency')] public $property3; - /** - * @Inject(name="foo") - */ + #[Inject(name: 'foo')] public $property4; - /** - * @Inject - */ + #[Inject] public LazyDependency $property5; public $constructorParam1; @@ -67,11 +57,8 @@ public function __construct(Class2 $param1, Interface1 $param2, LazyDependency $ /** * Tests optional parameter is not overridden. - * - * @Inject - * @param Class2 $param1 - * @throws \Exception */ + #[Inject] public function method1(Class2 $param1, $optional = true) { $this->method1Param1 = $param1; @@ -83,10 +70,8 @@ public function method1(Class2 $param1, $optional = true) /** * Tests automatic resolution of parameter based on the type-hinting. - * - * @Inject - * @param Interface1 $param1 */ + #[Inject] public function method2(Interface1 $param1) { $this->method2Param1 = $param1; @@ -95,9 +80,9 @@ public function method2(Interface1 $param1) /** * Tests defining parameters. * - * @Inject({"namedDependency", "foo"}) * @param string $param1 */ + #[Inject(['namedDependency', 'foo'])] public function method3($param1, $param2) { $this->method3Param1 = $param1; @@ -106,10 +91,8 @@ public function method3($param1, $param2) /** * Tests injecting a lazy dependency. - * - * @Inject - * @param LazyDependency $param1 */ + #[Inject] public function method4(LazyDependency $param1) { $this->method4Param1 = $param1; diff --git a/tests/IntegrationTest/Fixtures/InheritanceTest/BaseClass.php b/tests/IntegrationTest/Fixtures/InheritanceTest/BaseClass.php index cbb825e43..170cb8d5c 100644 --- a/tests/IntegrationTest/Fixtures/InheritanceTest/BaseClass.php +++ b/tests/IntegrationTest/Fixtures/InheritanceTest/BaseClass.php @@ -4,16 +4,14 @@ namespace DI\Test\IntegrationTest\Fixtures\InheritanceTest; -use DI\Annotation\Inject; +use DI\Attribute\Inject; /** * Fixture class. */ abstract class BaseClass { - /** - * @Inject - */ + #[Inject] public Dependency $property1; public Dependency $property2; @@ -25,9 +23,7 @@ public function __construct(Dependency $param1) $this->property3 = $param1; } - /** - * @Inject - */ + #[Inject] public function setProperty2(Dependency $property2) { $this->property2 = $property2; diff --git a/tests/IntegrationTest/Fixtures/InheritanceTest/SubClass.php b/tests/IntegrationTest/Fixtures/InheritanceTest/SubClass.php index ebfad0543..ae30fcc2c 100644 --- a/tests/IntegrationTest/Fixtures/InheritanceTest/SubClass.php +++ b/tests/IntegrationTest/Fixtures/InheritanceTest/SubClass.php @@ -4,15 +4,13 @@ namespace DI\Test\IntegrationTest\Fixtures\InheritanceTest; -use DI\Annotation\Inject; +use DI\Attribute\Inject; /** * Fixture class. */ class SubClass extends BaseClass { - /** - * @Inject - */ + #[Inject] public Dependency $property4; } diff --git a/tests/IntegrationTest/Fixtures/Interface1.php b/tests/IntegrationTest/Fixtures/Interface1.php index 662821018..b39f2fdf9 100644 --- a/tests/IntegrationTest/Fixtures/Interface1.php +++ b/tests/IntegrationTest/Fixtures/Interface1.php @@ -4,12 +4,12 @@ namespace DI\Test\IntegrationTest\Fixtures; -use DI\Annotation\Injectable; +use DI\Attribute\Injectable; /** * Fixture interface. - * @Injectable */ +#[Injectable] interface Interface1 { } diff --git a/tests/IntegrationTest/Fixtures/LazyDependency.php b/tests/IntegrationTest/Fixtures/LazyDependency.php index 8dcb1d4c2..106acd3a7 100644 --- a/tests/IntegrationTest/Fixtures/LazyDependency.php +++ b/tests/IntegrationTest/Fixtures/LazyDependency.php @@ -4,18 +4,15 @@ namespace DI\Test\IntegrationTest\Fixtures; -use DI\Annotation\Injectable; +use DI\Attribute\Injectable; /** * Fixture class. - * @Injectable(lazy=true) */ +#[Injectable(lazy: true)] class LazyDependency { - /** - * @return bool - */ - public function getValue() + public function getValue(): bool { return true; } diff --git a/tests/IntegrationTest/InheritanceTest.php b/tests/IntegrationTest/InheritanceTest.php index c22ff75a5..a1aa84377 100644 --- a/tests/IntegrationTest/InheritanceTest.php +++ b/tests/IntegrationTest/InheritanceTest.php @@ -22,7 +22,7 @@ class InheritanceTest extends BaseContainerTest public function test_dependency_is_injected_if_injection_defined_on_parent_class_with_config(ContainerBuilder $builder) { $builder->useAutowiring(false); - $builder->useAnnotations(false); + $builder->useAttributes(false); $builder->addDefinitions([ Dependency::class => \DI\create(), BaseClass::class => \DI\create(SubClass::class) @@ -51,10 +51,10 @@ public function test_dependency_is_injected_if_injection_defined_on_parent_class * * @dataProvider provideContainer */ - public function test_dependency_is_injected_if_injection_defined_on_parent_class_with_annotations(ContainerBuilder $builder) + public function test_dependency_is_injected_if_injection_defined_on_parent_class_with_attributes(ContainerBuilder $builder) { $builder->useAutowiring(true); - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->addDefinitions([ BaseClass::class => \DI\get(SubClass::class), ]); @@ -76,7 +76,7 @@ public function test_dependency_is_injected_if_injection_defined_on_parent_class public function test_dependency_is_injected_if_injection_defined_on_base_class_with_config(ContainerBuilder $builder) { $builder->useAutowiring(false); - $builder->useAnnotations(false); + $builder->useAttributes(false); $builder->addDefinitions([ Dependency::class => \DI\create(), BaseClass::class => \DI\create(SubClass::class) @@ -105,10 +105,10 @@ public function test_dependency_is_injected_if_injection_defined_on_base_class_w * * @dataProvider provideContainer */ - public function test_dependency_is_injected_if_injection_defined_on_base_class_with_annotations(ContainerBuilder $builder) + public function test_dependency_is_injected_if_injection_defined_on_base_class_with_attributes(ContainerBuilder $builder) { $builder->useAutowiring(true); - $builder->useAnnotations(true); + $builder->useAttributes(true); $builder->addDefinitions([ BaseClass::class => \DI\get(SubClass::class), ]); diff --git a/tests/IntegrationTest/Issues/Issue72/Class1.php b/tests/IntegrationTest/Issues/Issue72/Class1.php index 74afcb214..2405c56b7 100644 --- a/tests/IntegrationTest/Issues/Issue72/Class1.php +++ b/tests/IntegrationTest/Issues/Issue72/Class1.php @@ -4,15 +4,13 @@ namespace DI\Test\IntegrationTest\Issues\Issue72; -use DI\Annotation\Inject; +use DI\Attribute\Inject; class Class1 { public $arg1; - /** - * @Inject({"service1"}) - */ + #[Inject(['service1'])] public function __construct(\stdClass $arg1) { $this->arg1 = $arg1; diff --git a/tests/IntegrationTest/Issues/Issue72Test.php b/tests/IntegrationTest/Issues/Issue72Test.php index ea40ab8f6..47d3b7509 100644 --- a/tests/IntegrationTest/Issues/Issue72Test.php +++ b/tests/IntegrationTest/Issues/Issue72Test.php @@ -22,7 +22,7 @@ class Issue72Test extends BaseContainerTest public function annotationDefinitionShouldOverrideReflectionDefinition(ContainerBuilder $builder) { $builder->useAutowiring(true); - $builder->useAnnotations(true); + $builder->useAttributes(true); $container = $builder->build(); $value = new \stdClass(); @@ -42,7 +42,7 @@ public function annotationDefinitionShouldOverrideReflectionDefinition(Container public function arrayDefinitionShouldOverrideReflectionDefinition(ContainerBuilder $builder) { $builder->useAutowiring(true); - $builder->useAnnotations(false); + $builder->useAttributes(false); // Override to 'service2' in the definition file $builder->addDefinitions(__DIR__ . '/Issue72/definitions.php'); @@ -62,7 +62,7 @@ public function arrayDefinitionShouldOverrideReflectionDefinition(ContainerBuild public function arrayDefinitionShouldOverrideAnnotationDefinition(ContainerBuilder $builder) { $builder->useAutowiring(false); - $builder->useAnnotations(true); + $builder->useAttributes(true); // Override 'service1' to 'service2' in the definition file $builder->addDefinitions(__DIR__ . '/Issue72/definitions.php'); @@ -82,7 +82,7 @@ public function arrayDefinitionShouldOverrideAnnotationDefinition(ContainerBuild public function arrayDefinitionShouldOverrideAnotherArrayDefinition(ContainerBuilder $builder) { $builder->useAutowiring(false); - $builder->useAnnotations(false); + $builder->useAttributes(false); // Override 'service1' to 'service2' in the definition file $builder->addDefinitions(__DIR__ . '/Issue72/definitions.php'); @@ -109,7 +109,7 @@ public function phpDefinitionShouldOverrideArrayDefinition(ContainerBuilder $bui } $builder->useAutowiring(false); - $builder->useAnnotations(false); + $builder->useAttributes(false); $builder->addDefinitions(__DIR__ . '/Issue72/definitions.php'); $container = $builder->build(); diff --git a/tests/PerformanceTest/autowire.php b/tests/PerformanceTest/autowire.php index ec2171f52..97c2be1fd 100644 --- a/tests/PerformanceTest/autowire.php +++ b/tests/PerformanceTest/autowire.php @@ -10,7 +10,7 @@ $builder = new ContainerBuilder(); $builder->useAutowiring(true); -$builder->useAnnotations(false); +$builder->useAttributes(false); $builder->addDefinitions(__DIR__ . '/get/config.php'); $builder->enableCompilation(__DIR__ . '/tmp', 'Get'); $container = $builder->build(); diff --git a/tests/PerformanceTest/call.php b/tests/PerformanceTest/call.php index 8e6722d63..017cd7946 100644 --- a/tests/PerformanceTest/call.php +++ b/tests/PerformanceTest/call.php @@ -7,7 +7,7 @@ $builder = new ContainerBuilder(); $builder->useAutowiring(true); -$builder->useAnnotations(false); +$builder->useAttributes(false); $builder->enableCompilation(__DIR__ . '/tmp', 'Call'); $builder->addDefinitions([ 'link' => 'Hello', diff --git a/tests/PerformanceTest/factory.php b/tests/PerformanceTest/factory.php index 2f3145457..c1ea296f8 100644 --- a/tests/PerformanceTest/factory.php +++ b/tests/PerformanceTest/factory.php @@ -15,7 +15,7 @@ class Bar $builder = new ContainerBuilder(); $builder->useAutowiring(false); -$builder->useAnnotations(false); +$builder->useAttributes(false); $builder->enableCompilation(__DIR__ . '/tmp', 'Factory'); $builder->addDefinitions(__DIR__ . '/factory/config.php'); diff --git a/tests/PerformanceTest/get-cache.php b/tests/PerformanceTest/get-cache.php index b993766d1..2ddf15034 100644 --- a/tests/PerformanceTest/get-cache.php +++ b/tests/PerformanceTest/get-cache.php @@ -19,7 +19,7 @@ for ($i = 0; $i < 100; $i++) { $builder = new ContainerBuilder(); $builder->useAutowiring(true); - $builder->useAnnotations(false); + $builder->useAttributes(false); $builder->addDefinitions(__DIR__ . '/get/config.php'); if ($compile) { $builder->enableCompilation(__DIR__ . '/tmp/', "Container$i"); diff --git a/tests/PerformanceTest/get-object.php b/tests/PerformanceTest/get-object.php index fd523af57..aa6922e3f 100644 --- a/tests/PerformanceTest/get-object.php +++ b/tests/PerformanceTest/get-object.php @@ -8,7 +8,7 @@ $builder = new ContainerBuilder(); $builder->useAutowiring(true); -$builder->useAnnotations(false); +$builder->useAttributes(false); $builder->addDefinitions(__DIR__ . '/get-object/config.php'); $builder->enableCompilation(__DIR__ . '/tmp', 'GetObject'); $container = $builder->build(); diff --git a/tests/PerformanceTest/get.php b/tests/PerformanceTest/get.php index ec2171f52..97c2be1fd 100644 --- a/tests/PerformanceTest/get.php +++ b/tests/PerformanceTest/get.php @@ -10,7 +10,7 @@ $builder = new ContainerBuilder(); $builder->useAutowiring(true); -$builder->useAnnotations(false); +$builder->useAttributes(false); $builder->addDefinitions(__DIR__ . '/get/config.php'); $builder->enableCompilation(__DIR__ . '/tmp', 'Get'); $container = $builder->build(); diff --git a/tests/UnitTest/Annotation/Fixtures/Dependency.php b/tests/UnitTest/Annotation/Fixtures/Dependency.php deleted file mode 100644 index 48120f42c..000000000 --- a/tests/UnitTest/Annotation/Fixtures/Dependency.php +++ /dev/null @@ -1,9 +0,0 @@ -annotationReader = $definitionReader->getAnnotationReader(); - $this->reflectionClass = new ReflectionClass(InjectFixture::class); - } - - public function testProperty1() - { - $property = $this->reflectionClass->getProperty('property1'); - /** @var $annotation Inject */ - $annotation = $this->annotationReader->getPropertyAnnotation($property, Inject::class); - - $this->assertInstanceOf(Inject::class, $annotation); - $this->assertEquals('foo', $annotation->getName()); - } - - public function testProperty2() - { - $property = $this->reflectionClass->getProperty('property2'); - /** @var $annotation Inject */ - $annotation = $this->annotationReader->getPropertyAnnotation($property, Inject::class); - - $this->assertInstanceOf(Inject::class, $annotation); - $this->assertNull($annotation->getName()); - } - - public function testProperty3() - { - $property = $this->reflectionClass->getProperty('property3'); - /** @var $annotation Inject */ - $annotation = $this->annotationReader->getPropertyAnnotation($property, Inject::class); - - $this->assertInstanceOf(Inject::class, $annotation); - $this->assertEquals('foo', $annotation->getName()); - } - - public function testMethod1() - { - $method = $this->reflectionClass->getMethod('method1'); - /** @var $annotation Inject */ - $annotation = $this->annotationReader->getMethodAnnotation($method, Inject::class); - - $this->assertInstanceOf(Inject::class, $annotation); - $this->assertEmpty($annotation->getParameters()); - } - - public function testMethod2() - { - $method = $this->reflectionClass->getMethod('method2'); - /** @var $annotation Inject */ - $annotation = $this->annotationReader->getMethodAnnotation($method, Inject::class); - $parameters = $annotation->getParameters(); - - $this->assertInstanceOf(Inject::class, $annotation); - $this->assertCount(2, $parameters); - $this->assertEquals('foo', $parameters[0]); - $this->assertEquals('bar', $parameters[1]); - } - - public function testMethod3() - { - $method = $this->reflectionClass->getMethod('method3'); - /** @var $annotation Inject */ - $annotation = $this->annotationReader->getMethodAnnotation($method, Inject::class); - $parameters = $annotation->getParameters(); - - $this->assertInstanceOf(Inject::class, $annotation); - $this->assertCount(1, $parameters); - - $this->assertArrayHasKey('str1', $parameters); - $this->assertEquals('foo', $parameters['str1']); - } - - public function testInvalidAnnotation() - { - $this->expectException(InvalidAnnotation::class); - $this->expectExceptionMessage('@Inject({"param" = "value"}) expects "value" to be a string, [] given.'); - $method = $this->reflectionClass->getMethod('method4'); - $this->annotationReader->getMethodAnnotation($method, Inject::class); - } - - /** - * Inject annotation should work even if not imported. - */ - public function testNonImportedAnnotation() - { - $class = new ReflectionClass(NonImportedInjectFixture::class); - $property = $class->getProperty('property1'); - /** @var $annotation Inject */ - $annotation = $this->annotationReader->getPropertyAnnotation($property, Inject::class); - - $this->assertInstanceOf(Inject::class, $annotation); - } - - /** - * Inject annotation should work even if there are other weird annotations in the file. - */ - public function testMixedAnnotations() - { - $class = new ReflectionClass(MixedAnnotationsFixture::class); - $property = $class->getProperty('property1'); - /** @var $annotation Inject */ - $annotation = $this->annotationReader->getPropertyAnnotation($property, Inject::class); - - $this->assertInstanceOf(Inject::class, $annotation); - } -} diff --git a/tests/UnitTest/Annotation/InjectableTest.php b/tests/UnitTest/Annotation/InjectableTest.php deleted file mode 100644 index 1c23efc9d..000000000 --- a/tests/UnitTest/Annotation/InjectableTest.php +++ /dev/null @@ -1,52 +0,0 @@ -annotationReader = $definitionReader->getAnnotationReader(); - } - - public function testEmptyAnnotation() - { - $class = new ReflectionClass(Injectable1::class); - /** @var $annotation Injectable */ - $annotation = $this->annotationReader->getClassAnnotation($class, Injectable::class); - - $this->assertInstanceOf(Injectable::class, $annotation); - $this->assertNull($annotation->isLazy()); - } - - public function testLazy() - { - $class = new ReflectionClass(Injectable2::class); - /** @var $annotation Injectable */ - $annotation = $this->annotationReader->getClassAnnotation($class, Injectable::class); - - $this->assertInstanceOf(Injectable::class, $annotation); - $this->assertTrue($annotation->isLazy()); - } -} diff --git a/tests/UnitTest/Attributes/InjectTest.php b/tests/UnitTest/Attributes/InjectTest.php index a2a28e6ce..3deceef23 100644 --- a/tests/UnitTest/Attributes/InjectTest.php +++ b/tests/UnitTest/Attributes/InjectTest.php @@ -8,7 +8,7 @@ use DI\Test\UnitTest\Attributes\Fixtures\InjectFixture; use PHPUnit\Framework\TestCase; use ReflectionClass; -use DI\Definition\Exception\InvalidAnnotation; +use DI\Definition\Exception\InvalidAttribute; /** * Inject annotation test class. @@ -95,7 +95,7 @@ public function testMethod3() public function testInvalidAnnotation() { - $this->expectException(InvalidAnnotation::class); + $this->expectException(InvalidAttribute::class); $this->expectExceptionMessage("#[Inject(['param' => 'value'])] expects \"value\" to be a string, [] given."); $method = $this->reflectionClass->getMethod('method4'); $method->getAttributes(Inject::class)[0]->newInstance(); diff --git a/tests/UnitTest/ContainerBuilderTest.php b/tests/UnitTest/ContainerBuilderTest.php index 816bb869a..1a863cb76 100644 --- a/tests/UnitTest/ContainerBuilderTest.php +++ b/tests/UnitTest/ContainerBuilderTest.php @@ -207,10 +207,10 @@ public function should_have_a_fluent_interface() { $builder = new ContainerBuilder(); - $result = $builder->useAnnotations(false); + $result = $builder->useAttributes(false); $this->assertSame($builder, $result); - $result = $builder->useAnnotations(true); + $result = $builder->useAttributes(true); $this->assertSame($builder, $result); $result = $builder->useAutowiring(false); diff --git a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php b/tests/UnitTest/Definition/Source/AttributeBasedAutowiringTest.php similarity index 72% rename from tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php rename to tests/UnitTest/Definition/Source/AttributeBasedAutowiringTest.php index 61a1aefdb..0204e2ec6 100644 --- a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php +++ b/tests/UnitTest/Definition/Source/AttributeBasedAutowiringTest.php @@ -4,13 +4,13 @@ namespace DI\Test\UnitTest\Definition\Source; -use DI\Definition\Reference; use DI\Definition\Definition; +use DI\Definition\Exception\InvalidAttribute; use DI\Definition\ObjectDefinition; use DI\Definition\ObjectDefinition\MethodInjection; use DI\Definition\ObjectDefinition\PropertyInjection; -use DI\Definition\Source\AnnotationBasedAutowiring; -use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture; +use DI\Definition\Reference; +use DI\Definition\Source\AttributeBasedAutowiring; use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture2; use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture3; use DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture4; @@ -19,56 +19,56 @@ 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 DI\Test\UnitTest\Definition\Source\Fixtures\AttributeFixture; use PHPUnit\Framework\TestCase; -use DI\Definition\Exception\InvalidAnnotation; /** - * @covers \DI\Definition\Source\AnnotationBasedAutowiring + * @covers \DI\Definition\Source\AttributeBasedAutowiring */ -class AnnotationBasedAutowiringTest extends TestCase +class AttributeBasedAutowiringTest extends TestCase { public function testUnknownClass() { - $this->assertNull((new AnnotationBasedAutowiring)->autowire('foo')); + $this->assertNull((new AttributeBasedAutowiring)->autowire('foo')); } public function testProperty1() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertInstanceOf(Definition::class, $definition); $properties = $definition->getPropertyInjections(); $this->assertInstanceOf(PropertyInjection::class, $properties['property1']); $property = $properties['property1']; - $this->assertEquals('property1', $property->getPropertyName()); + $this->assertSame('property1', $property->getPropertyName()); $this->assertEquals(new Reference('foo'), $property->getValue()); } public function testUnannotatedProperty() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertNotHasPropertyInjection($definition, 'unannotatedProperty'); } public function testStaticProperty() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertNotHasPropertyInjection($definition, 'staticProperty'); } public function testUnguessableProperty() { - $this->expectException(InvalidAnnotation::class); - $this->expectExceptionMessage('@Inject found on property DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture4::property but unable to guess what to inject, please add a type to the property'); - (new AnnotationBasedAutowiring)->autowire(AnnotationFixture4::class); + $this->expectException(InvalidAttribute::class); + $this->expectExceptionMessage('#[Inject] found on property DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture4::property but unable to guess what to inject, please add a type to the property'); + (new AttributeBasedAutowiring)->autowire(AnnotationFixture4::class); } public function testTypedProperty() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureTypedProperties::class); + $definition = (new AttributeBasedAutowiring)->autowire(AnnotationFixtureTypedProperties::class); $this->assertNotHasPropertyInjection($definition, 'typeAndNoInject'); $this->assertHasPropertyInjection($definition, 'typedAndInject', AnnotationFixture2::class); @@ -77,13 +77,13 @@ public function testTypedProperty() public function testScalarTypedPropertiesFail() { - $this->expectException(InvalidAnnotation::class); - (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureScalarTypedProperty::class); + $this->expectException(InvalidAttribute::class); + (new AttributeBasedAutowiring)->autowire(AnnotationFixtureScalarTypedProperty::class); } public function testConstructor() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertInstanceOf(Definition::class, $definition); $constructorInjection = $definition->getConstructorInjection(); @@ -97,7 +97,7 @@ public function testConstructor() public function testMethod1() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertInstanceOf(Definition::class, $definition); $methodInjection = $this->getMethodInjection($definition, 'method1'); @@ -108,7 +108,7 @@ public function testMethod1() public function testMethod2() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertInstanceOf(Definition::class, $definition); $methodInjection = $this->getMethodInjection($definition, 'method2'); @@ -122,7 +122,7 @@ public function testMethod2() public function testMethod3() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertInstanceOf(Definition::class, $definition); $methodInjection = $this->getMethodInjection($definition, 'method3'); @@ -137,7 +137,7 @@ public function testMethod3() public function testMethod4() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertInstanceOf(Definition::class, $definition); $methodInjection = $this->getMethodInjection($definition, 'method4'); @@ -151,7 +151,7 @@ public function testMethod4() public function testMethod5() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertInstanceOf(Definition::class, $definition); $methodInjection = $this->getMethodInjection($definition, 'method5'); @@ -166,17 +166,14 @@ public function testMethod5() public function testUnannotatedMethod() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertNull($this->getMethodInjection($definition, 'unannotatedMethod')); } - /** - * @test - */ - public function optionalParametersShouldBeIgnored() + public function testOptionalParametersShouldBeIgnored() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $methodInjection = $this->getMethodInjection($definition, 'optionalParameter'); @@ -189,21 +186,21 @@ public function optionalParametersShouldBeIgnored() public function testStaticMethod() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AttributeFixture::class); $this->assertNull($this->getMethodInjection($definition, 'staticMethod')); } public function testInjectable() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationInjectableFixture::class); + $definition = (new AttributeBasedAutowiring)->autowire(AnnotationInjectableFixture::class); $this->assertInstanceOf(Definition::class, $definition); $this->assertTrue($definition->isLazy()); } - public function test_method_injection_with_primitive_type_causes_an_error() + public function testMethodInjectionWithPrimitiveTypeCausesAnError() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixture3::class); + $definition = (new AttributeBasedAutowiring)->autowire(AnnotationFixture3::class); $this->assertInstanceOf(Definition::class, $definition); $methodInjection = $this->getMethodInjection($definition, 'method1'); @@ -219,14 +216,14 @@ public function test_method_injection_with_primitive_type_causes_an_error() public function testFailWithTypeError() { - $this->expectException(InvalidAnnotation::class); - $this->expectExceptionMessage('@Inject found on property DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture5::property but unable to guess what to inject, the type of the property does not look like a valid class or interface name'); - (new AnnotationBasedAutowiring)->autowire(AnnotationFixture5::class); + $this->expectException(InvalidAttribute::class); + $this->expectExceptionMessage('#[Inject] found on property DI\Test\UnitTest\Definition\Source\Fixtures\AnnotationFixture5::property but unable to guess what to inject, the type of the property does not look like a valid class or interface name'); + (new AttributeBasedAutowiring)->autowire(AnnotationFixture5::class); } public function testMergedWithParentDefinition() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureChild::class); + $definition = (new AttributeBasedAutowiring)->autowire(AnnotationFixtureChild::class); $this->assertHasPropertyInjection($definition, 'propertyChild'); $this->assertNotNull($this->getMethodInjection($definition, 'methodChild')); @@ -241,11 +238,11 @@ public function testMergedWithParentDefinition() */ public function testReadParentPrivateProperties() { - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureChild::class); + $definition = (new AttributeBasedAutowiring)->autowire(AnnotationFixtureChild::class); $this->assertHasPropertyInjection($definition, 'propertyParentPrivate'); } - private function getMethodInjection(ObjectDefinition $definition, $name): ?MethodInjection + private function getMethodInjection(ObjectDefinition $definition, $name) : ?MethodInjection { $methodInjections = $definition->getMethodInjections(); foreach ($methodInjections as $methodInjection) { @@ -262,10 +259,9 @@ private function assertHasPropertyInjection(ObjectDefinition $definition, $prope $propertyInjections = $definition->getPropertyInjections(); foreach ($propertyInjections as $propertyInjection) { if ($propertyInjection->getPropertyName() === $propertyName) { - if ($expectedType !== null) { $this->assertInstanceOf(Reference::class, $propertyInjection->getValue()); - $this->assertEquals( + $this->assertSame( $expectedType, $propertyInjection->getValue()->getTargetEntryName(), 'Property injected with the right type' diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture3.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture3.php index 437c3bef9..90d0a965e 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture3.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture3.php @@ -4,11 +4,11 @@ namespace DI\Test\UnitTest\Definition\Source\Fixtures; +use DI\Attribute\Inject; + class AnnotationFixture3 { - /** - * @Inject - */ + #[Inject] public function method1(AnnotationFixture2 $param1, bool $param2) { } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture4.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture4.php index f51d9b008..5940ee7c5 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture4.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture4.php @@ -4,10 +4,10 @@ namespace DI\Test\UnitTest\Definition\Source\Fixtures; +use DI\Attribute\Inject; + class AnnotationFixture4 { - /** - * @Inject - */ + #[Inject] public $property; } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture5.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture5.php index 64d72a862..0d443e238 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture5.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture5.php @@ -4,11 +4,11 @@ namespace DI\Test\UnitTest\Definition\Source\Fixtures; +use DI\Attribute\Inject; + class AnnotationFixture5 { - /** - * @Inject - */ + #[Inject] public foobar $property; public function __construct(foobar $foo) diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureChild.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureChild.php index b0a17e097..3d67cf021 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureChild.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureChild.php @@ -4,21 +4,17 @@ namespace DI\Test\UnitTest\Definition\Source\Fixtures; -use DI\Annotation\Inject; +use DI\Attribute\Inject; /** * Used to check that child classes also have the injections of the parent classes. */ class AnnotationFixtureChild extends AnnotationFixtureParent { - /** - * @Inject("foo") - */ + #[Inject('foo')] protected $propertyChild; - /** - * @Inject - */ + #[Inject] public function methodChild() { } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureParent.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureParent.php index a3f183a7a..a261a9366 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureParent.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureParent.php @@ -4,26 +4,20 @@ namespace DI\Test\UnitTest\Definition\Source\Fixtures; -use DI\Annotation\Inject; +use DI\Attribute\Inject; /** * Used to check that child classes also have the injections of the parent classes. */ class AnnotationFixtureParent { - /** - * @Inject("foo") - */ + #[Inject('foo')] protected $propertyParent; - /** - * @Inject("foo") - */ + #[Inject('foo')] private $propertyParentPrivate; - /** - * @Inject - */ + #[Inject] public function methodParent() { } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureScalarTypedProperty.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureScalarTypedProperty.php index 7bf7f9dc8..6e64be460 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureScalarTypedProperty.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureScalarTypedProperty.php @@ -4,10 +4,10 @@ namespace DI\Test\UnitTest\Definition\Source\Fixtures; +use DI\Attribute\Inject; + class AnnotationFixtureScalarTypedProperty { - /** - * @Inject - */ + #[Inject] protected int $scalarTypeAndInject; } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureTypedProperties.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureTypedProperties.php index 8bde283fe..443d5f4a3 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureTypedProperties.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixtureTypedProperties.php @@ -4,17 +4,15 @@ namespace DI\Test\UnitTest\Definition\Source\Fixtures; +use DI\Attribute\Inject; + class AnnotationFixtureTypedProperties { protected AnnotationFixture2 $typedButNoInject; - /** - * @Inject - */ + #[Inject] protected AnnotationFixture2 $typedAndInject; - /** - * @Inject("name") - */ + #[Inject('name')] protected AnnotationFixture2 $typedAndNamed; } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationInjectableFixture.php b/tests/UnitTest/Definition/Source/Fixtures/AnnotationInjectableFixture.php index 19f1541a2..607dfbebd 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationInjectableFixture.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AnnotationInjectableFixture.php @@ -4,9 +4,9 @@ namespace DI\Test\UnitTest\Definition\Source\Fixtures; -/** - * @Injectable(lazy=true) - */ +use DI\Attribute\Injectable; + +#[Injectable(lazy: true)] class AnnotationInjectableFixture { } diff --git a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture.php b/tests/UnitTest/Definition/Source/Fixtures/AttributeFixture.php similarity index 67% rename from tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture.php rename to tests/UnitTest/Definition/Source/Fixtures/AttributeFixture.php index 0ae309373..f768e2a87 100644 --- a/tests/UnitTest/Definition/Source/Fixtures/AnnotationFixture.php +++ b/tests/UnitTest/Definition/Source/Fixtures/AttributeFixture.php @@ -4,76 +4,60 @@ namespace DI\Test\UnitTest\Definition\Source\Fixtures; -use DI\Annotation\Inject; +use DI\Attribute\Inject; -class AnnotationFixture +class AttributeFixture { - /** - * @Inject("foo") - */ + #[Inject('foo')] protected $property1; - /** - * @Inject - */ + #[Inject] protected AnnotationFixture2 $property2; - /** - * @Inject(name="foo") - */ + #[Inject(name: 'foo')] protected $property3; protected $unannotatedProperty; /** * Static property shouldn't be injected. - * - * @Inject("foo") */ + #[Inject('foo')] protected static $staticProperty; - /** - * @Inject({"foo", "bar"}) - */ + #[Inject(['foo', 'bar'])] public function __construct($param1, $param2) { } - /** - * @Inject - */ + #[Inject] public function method1() { } - /** - * @Inject({"foo", "bar"}) - */ + #[Inject(['foo', 'bar'])] public function method2($param1, $param2) { } - /** - * @Inject - * @param $param1 - */ + #[Inject] public function method3(AnnotationFixture2 $param1) { } /** - * @Inject({"foo", "bar"}) * @param AnnotationFixture2 $param1 * @param AnnotationFixture2 $param2 */ + #[Inject(['foo', 'bar'])] public function method4($param1, $param2) { } /** * Indexed by name, param1 not specified:. - * @Inject({"param2" = "bar"}) */ + #[Inject(['param2' => 'bar'])] public function method5($param1, $param2) { } @@ -82,16 +66,12 @@ public function unannotatedMethod() { } - /** - * @Inject({"foo"}) - */ + #[Inject(['foo'])] public function optionalParameter(\stdClass $optional1 = null, \stdClass $optional2 = null) { } - /** - * @Inject - */ + #[Inject] public static function staticMethod() { } diff --git a/tests/UnitTest/Fixtures/Class1CircularDependencies.php b/tests/UnitTest/Fixtures/Class1CircularDependencies.php index 75f77dfa1..0adad772c 100644 --- a/tests/UnitTest/Fixtures/Class1CircularDependencies.php +++ b/tests/UnitTest/Fixtures/Class1CircularDependencies.php @@ -4,13 +4,13 @@ namespace DI\Test\UnitTest\Fixtures; +use DI\Attribute\Inject; + /** * Fixture class for testing circular dependencies. */ class Class1CircularDependencies { - /** - * @Inject - */ + #[Inject] public Class2CircularDependencies $class2; } diff --git a/tests/UnitTest/Fixtures/Class2CircularDependencies.php b/tests/UnitTest/Fixtures/Class2CircularDependencies.php index c82d919a9..5e9d52bca 100644 --- a/tests/UnitTest/Fixtures/Class2CircularDependencies.php +++ b/tests/UnitTest/Fixtures/Class2CircularDependencies.php @@ -4,14 +4,13 @@ namespace DI\Test\UnitTest\Fixtures; +use DI\Attribute\Inject; + /** * Fixture class for testing circular dependencies. */ class Class2CircularDependencies { - /** - * @Inject - * @var Class1CircularDependencies - */ + #[Inject] public Class1CircularDependencies $class1; } diff --git a/tests/UnitTest/Fixtures/Singleton.php b/tests/UnitTest/Fixtures/Singleton.php index 8b6b2ff2b..ee1c50c48 100644 --- a/tests/UnitTest/Fixtures/Singleton.php +++ b/tests/UnitTest/Fixtures/Singleton.php @@ -4,11 +4,9 @@ namespace DI\Test\UnitTest\Fixtures; -use DI\Annotation\Injectable; +use DI\Attribute\Injectable; -/** - * @Injectable - */ +#[Injectable] class Singleton { } From 6e8d9f56810ac77aa278c0974a31988062609e8d Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sun, 21 Aug 2022 14:44:36 +0200 Subject: [PATCH 38/45] Fix build --- src/FactoryInterface.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FactoryInterface.php b/src/FactoryInterface.php index 22852f29c..3486b900b 100644 --- a/src/FactoryInterface.php +++ b/src/FactoryInterface.php @@ -22,7 +22,6 @@ interface FactoryInterface * parameters to specific values. Parameters not defined in this array will * be automatically resolved. * - * @return mixed * @throws \InvalidArgumentException The name parameter must be of type string. * @throws DependencyException Error while resolving the entry. * @throws NotFoundException No entry or class found for the given name. From 8948ffbc43f3e19c66d908593b6a94b2fc1fe6f6 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sun, 8 Jan 2023 20:14:13 +0100 Subject: [PATCH 39/45] Prepare the blog post for the 7.0 release --- doc/migration/7.0.md | 2 +- news/23-php-di-7-0-released.md | 23 +++++++++++++++++++++++ website/blog.twig | 15 +++++++++++++++ website/blogpost.twig | 2 +- website/home.twig | 2 +- 5 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 news/23-php-di-7-0-released.md diff --git a/doc/migration/7.0.md b/doc/migration/7.0.md index e45a2f283..b5705b41d 100644 --- a/doc/migration/7.0.md +++ b/doc/migration/7.0.md @@ -15,7 +15,7 @@ PHP-DI now requires PHP 8.0 or greater. If you are using an older version, you c ## Container creation -The container can now be created with sane defaults without using the `ContainerBuilder` class: +The container can now be created with sane defaults without using the `ContainerBuilder` class (though it's not mandatory): ```php $container = new \DI\Container(); diff --git a/news/23-php-di-7-0-released.md b/news/23-php-di-7-0-released.md new file mode 100644 index 000000000..8bdbe554c --- /dev/null +++ b/news/23-php-di-7-0-released.md @@ -0,0 +1,23 @@ +--- +layout: blogpost +title: PHP-DI 7.0 released +author: Matthieu Napoli +date: January 12th 2023 +--- + +I am very happy to announce that PHP-DI 7.0 has been released! + +**If you have never heard of PHP-DI visit [the home page](../) first** to get an overview of what PHP-DI can do for you. + +I'll make this one short and to the point. PHP-DI 7 is a maturation of v6 to support modern PHP versions and their new features: + +- PHP 8.0 and greater is supported +- `@Inject` phpdoc annotations have been replaced by the native PHP attribute `#[Inject]` +- PSR-11 2.0 compatibility +- The codebase and the API exposed is now much more typed (thanks to the new PHP features) + +If you are migrating from a 6.x version check out **the detailed [migration guide](../doc/migration/7.0.md)**. + +The documentation shown on [php-di.org](http://php-di.org) is now for the 7.0 version, the 6.x documentation can be found [here](https://github.com/PHP-DI/PHP-DI/tree/6.4/doc). + +If something isn't right in the package or the documentation, please [open an issue](https://github.com/PHP-DI/PHP-DI/issues/new) or a pull request. diff --git a/website/blog.twig b/website/blog.twig index 575d1bb80..2aa0976f9 100644 --- a/website/blog.twig +++ b/website/blog.twig @@ -12,6 +12,18 @@

Latest news

+
+

+ PHP-DI 7.0 released +

+ +

+ I am very happy to announce that PHP-DI 7.0 has been released. +

+ + Read More > +
+

PHP-DI 6.0 released @@ -257,6 +269,9 @@

    +
  • + PHP-DI 7.0 released +
  • PHP-DI 6.0 released
  • diff --git a/website/blogpost.twig b/website/blogpost.twig index c846a2668..079a1137e 100644 --- a/website/blogpost.twig +++ b/website/blogpost.twig @@ -6,7 +6,7 @@

    {{ title }}

    {{ content|raw }} diff --git a/website/home.twig b/website/home.twig index 76444f390..4537cc30e 100644 --- a/website/home.twig +++ b/website/home.twig @@ -6,7 +6,7 @@

    - PHP-DI 6 + PHP-DI 7

    The dependency injection container for humans From 921a1c85fa7a9d4ebf98282182f6643731f7ff65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sun, 8 Jan 2023 23:27:20 +0000 Subject: [PATCH 40/45] Remove non-analyzed vendor directory from Psalm ignores --- psalm.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/psalm.xml b/psalm.xml index 92f579ebb..eade0458b 100644 --- a/psalm.xml +++ b/psalm.xml @@ -7,9 +7,8 @@ xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" > - + - From be4a41afa4a6a9c04df9a431542989e511a8fb8f Mon Sep 17 00:00:00 2001 From: Jacob Dreesen Date: Mon, 9 Jan 2023 11:52:56 +0100 Subject: [PATCH 41/45] Fix typo --- website/less/algolia.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/less/algolia.less b/website/less/algolia.less index 8e00f3340..061a4befe 100644 --- a/website/less/algolia.less +++ b/website/less/algolia.less @@ -36,7 +36,7 @@ .algolia-docsearch-suggestion--highlight { color: @link-color; } -/* Highligted search terms in the main category headers */ +/* Highlighted search terms in the main category headers */ .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight { background-color: transparent; } From 39b2557cc21a1509689035eefdd45b4dcb6204f6 Mon Sep 17 00:00:00 2001 From: Jacob Dreesen Date: Mon, 9 Jan 2023 11:53:53 +0100 Subject: [PATCH 42/45] Fix typo --- doc/scopes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/scopes.md b/doc/scopes.md index f8f610e38..ae31ea469 100644 --- a/doc/scopes.md +++ b/doc/scopes.md @@ -19,7 +19,7 @@ Before: ```php return [ Form::class => create() - ->scope(Scope::PROTOTYPE), // a new form is created everytime it is injected + ->scope(Scope::PROTOTYPE), // a new form is created every time it is injected ]; class Service From d3e0057ddfda8d102043c12e5ac277adb17bcd94 Mon Sep 17 00:00:00 2001 From: Luc De Brouwer Date: Mon, 9 Jan 2023 14:36:32 +0000 Subject: [PATCH 43/45] Correct type hints to prevent tooling like PHPStan from raising issues. --- src/Definition/Helper/CreateDefinitionHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Definition/Helper/CreateDefinitionHelper.php b/src/Definition/Helper/CreateDefinitionHelper.php index 3959fe72b..57278c98b 100644 --- a/src/Definition/Helper/CreateDefinitionHelper.php +++ b/src/Definition/Helper/CreateDefinitionHelper.php @@ -68,7 +68,7 @@ public function lazy() : self * This method takes a variable number of arguments, example: * ->constructor($param1, $param2, $param3) * - * @param mixed[] $parameters Parameters to use for calling the constructor of the class. + * @param mixed $parameters Parameters to use for calling the constructor of the class. * * @return $this */ @@ -104,7 +104,7 @@ public function property(string $property, mixed $value) : self * Can be used multiple times to declare multiple calls. * * @param string $method Name of the method to call. - * @param mixed[] $parameters Parameters to use for calling the method. + * @param mixed $parameters Parameters to use for calling the method. * * @return $this */ From 60116115fe6599b881f0832a29854d11e4c26cb0 Mon Sep 17 00:00:00 2001 From: Luc Date: Mon, 9 Jan 2023 15:21:20 +0000 Subject: [PATCH 44/45] Update src/Definition/Helper/CreateDefinitionHelper.php Co-authored-by: Jacob Dreesen --- src/Definition/Helper/CreateDefinitionHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Definition/Helper/CreateDefinitionHelper.php b/src/Definition/Helper/CreateDefinitionHelper.php index 57278c98b..b3e1d4949 100644 --- a/src/Definition/Helper/CreateDefinitionHelper.php +++ b/src/Definition/Helper/CreateDefinitionHelper.php @@ -104,7 +104,7 @@ public function property(string $property, mixed $value) : self * Can be used multiple times to declare multiple calls. * * @param string $method Name of the method to call. - * @param mixed $parameters Parameters to use for calling the method. + * @param mixed ...$parameters Parameters to use for calling the method. * * @return $this */ From 7a17403011231230ff77413856a1600716671cf6 Mon Sep 17 00:00:00 2001 From: Luc Date: Mon, 9 Jan 2023 15:21:26 +0000 Subject: [PATCH 45/45] Update src/Definition/Helper/CreateDefinitionHelper.php Co-authored-by: Jacob Dreesen --- src/Definition/Helper/CreateDefinitionHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Definition/Helper/CreateDefinitionHelper.php b/src/Definition/Helper/CreateDefinitionHelper.php index b3e1d4949..5d2190512 100644 --- a/src/Definition/Helper/CreateDefinitionHelper.php +++ b/src/Definition/Helper/CreateDefinitionHelper.php @@ -68,7 +68,7 @@ public function lazy() : self * This method takes a variable number of arguments, example: * ->constructor($param1, $param2, $param3) * - * @param mixed $parameters Parameters to use for calling the constructor of the class. + * @param mixed ...$parameters Parameters to use for calling the constructor of the class. * * @return $this */