From 27cd8b23f6aa0d6c1aa81a2e5133b09b7c4a62d4 Mon Sep 17 00:00:00 2001 From: Michal Kruczek Date: Wed, 10 Jan 2024 11:38:07 +0100 Subject: [PATCH 1/3] feat: php-cs-fixer - removing deprecations 1. Detected deprecations in use: - Rule "braces" is deprecated. Use "single_space_around_construct", "control_structure_braces", "control_structure_continuation_position", "declare_parentheses", "no_multiple_statements_per_line", "curly_braces_position", "statement_indentation" and "no_extra_blank_lines" instead. 2. Detected deprecations in use: - Rule "curly_braces_position" is deprecated. Use "braces_position" instead. --- .php-cs-fixer.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 29ef69ef..33f4467d 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -15,9 +15,14 @@ '@Symfony' => true, '@Symfony:risky' => true, 'array_syntax' => ['syntax' => 'short'], - 'braces' => [ - 'allow_single_line_closure' => true, - ], + 'single_space_around_construct' => true, + 'control_structure_braces' => true, + 'control_structure_continuation_position' => true, + 'declare_parentheses' => true, + 'no_multiple_statements_per_line' => true, + 'braces_position' => true, + 'statement_indentation' => true, + 'no_extra_blank_lines' => true, 'concat_space' => [ 'spacing' => 'one', ], From 9d6e0b30e51809f119616493ada23be8d1bbdf50 Mon Sep 17 00:00:00 2001 From: Maciej Holyszko <14310995+falkenhawk@users.noreply.github.com> Date: Fri, 26 Apr 2019 19:50:47 +0200 Subject: [PATCH 2/3] AnnotationBasedAutowiring with additional options for performance tweaks - adds possibility to disable features which are not used - useAnnotations(boolean) toggle on autowire() helper to enable/disable reading annotations on specific definitions --- src/ContainerBuilder.php | 9 ++- src/Definition/AutowireDefinition.php | 22 ++++++ .../Helper/AutowireDefinitionHelper.php | 30 ++++++++ .../Source/AttributeBasedAutowiring.php | 75 +++++++++++++++++-- 4 files changed, 126 insertions(+), 10 deletions(-) diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index 7a7285c7..d3a4a348 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -52,6 +52,10 @@ class ContainerBuilder private bool $useAutowiring = true; + private int $annotationsFlags = 0; + + private bool $ignorePhpDocErrors = false; + private bool $useAttributes = false; /** @@ -146,7 +150,7 @@ public function build() $this->compileToDirectory, $containerClass, $this->containerParentClass, - $this->useAutowiring + $this->useAutowiring || $this->useAttributes ); // Only load the file if it hasn't been already loaded // (the container can be created multiple times in the same process) @@ -216,11 +220,12 @@ public function useAutowiring(bool $bool) : self * * @return $this */ - public function useAttributes(bool $bool) : self + public function useAttributes(bool $bool, int $flags = 0) : self { $this->ensureNotLocked(); $this->useAttributes = $bool; + $this->annotationsFlags = $flags; return $this; } diff --git a/src/Definition/AutowireDefinition.php b/src/Definition/AutowireDefinition.php index 25dc3ecb..6bd75331 100644 --- a/src/Definition/AutowireDefinition.php +++ b/src/Definition/AutowireDefinition.php @@ -9,4 +9,26 @@ */ class AutowireDefinition extends ObjectDefinition { + /** + * @var bool|null + */ + protected $useAnnotations; + + /** + * Enable/disable reading annotations for this definition, regardless of a container configuration. + * @param bool $flag + */ + public function useAnnotations(bool $flag = true) + { + $this->useAnnotations = $flag; + } + + /** + * Returns boolean if the useAnnotation flag was explicitly set, otherwise null. + * @return bool|null + */ + public function isUsingAnnotations() + { + return $this->useAnnotations; + } } diff --git a/src/Definition/Helper/AutowireDefinitionHelper.php b/src/Definition/Helper/AutowireDefinitionHelper.php index 01b59e8f..7c677538 100644 --- a/src/Definition/Helper/AutowireDefinitionHelper.php +++ b/src/Definition/Helper/AutowireDefinitionHelper.php @@ -5,6 +5,7 @@ namespace DI\Definition\Helper; use DI\Definition\AutowireDefinition; +use DI\Definition\Definition; /** * Helps defining how to create an instance of a class using autowiring. @@ -15,6 +16,8 @@ class AutowireDefinitionHelper extends CreateDefinitionHelper { public const DEFINITION_CLASS = AutowireDefinition::class; + protected $useAnnotations; + /** * Defines a value for a specific argument of the constructor. * @@ -69,4 +72,31 @@ public function methodParameter(string $method, string|int $parameter, mixed $va return $this; } + + /** + * Define if entry should use annotation reader for reading dependencies. + * This is turned off by default if autowire() helper is used, and turned on if entry is not defined explicitly in the di config. + * @param bool $useAnnotations + * @return $this + */ + public function useAnnotations(bool $useAnnotations = true) + { + $this->useAnnotations = $useAnnotations; + + return $this; + } + + /** + * @return AutowireDefinition + */ + public function getDefinition(string $entryName) : Definition + { + /** @var AutowireDefinition $definition */ + $definition = parent::getDefinition($entryName); + if ($this->useAnnotations !== null) { + $definition->useAnnotations($this->useAnnotations); + } + + return $definition; + } } diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php index a3010280..0a7eacf1 100644 --- a/src/Definition/Source/AttributeBasedAutowiring.php +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -6,6 +6,7 @@ use DI\Attribute\Inject; use DI\Attribute\Injectable; +use DI\Definition\AutowireDefinition; use DI\Definition\Exception\InvalidAttribute; use DI\Definition\ObjectDefinition; use DI\Definition\ObjectDefinition\MethodInjection; @@ -28,9 +29,25 @@ */ class AttributeBasedAutowiring implements DefinitionSource, Autowiring { - /** - * @throws InvalidAttribute - */ + // Annotations configuration flags: + // enable on implicit definitions + const IMPLICIT = 1; + // enable on all autowire definitions (which are written in DI config) by default + const EXPLICIT = 2; + // read @Injectable annotations for classes + const INJECTABLE = 4; + // read @Inject annotations for properties + const PROPERTIES = 8; + // read @Inject annotations for methods' parameters + const METHODS = 16; + // all options enabled + const ALL = 31; + + public function __construct(private int $flags = 0) + { + $this->flags = $flags > 0 ? $flags : self::ALL; // all flags turned on by default + } + public function autowire(string $name, ObjectDefinition $definition = null) : ObjectDefinition|null { $className = $definition ? $definition->getClassName() : $name; @@ -40,16 +57,36 @@ public function autowire(string $name, ObjectDefinition $definition = null) : Ob } $definition = $definition ?: new ObjectDefinition($name); + $useAnnotations = $definition instanceof AutowireDefinition + ? ($definition->isUsingAnnotations() ?? ($this->flags & self::EXPLICIT)) + : ($this->flags & self::IMPLICIT); - $class = new ReflectionClass($className); + $class = null; + if ($useAnnotations && $this->flags >= self::INJECTABLE) { + $class = new ReflectionClass($className); $this->readInjectableAttribute($class, $definition); + if ($this->flags & self::INJECTABLE) { + $this->readInjectableAnnotation($class, $definition); + } - // Browse the class properties looking for annotated properties - $this->readProperties($class, $definition); + // Browse the class properties looking for annotated properties + if ($this->flags & self::PROPERTIES) { + $this->readProperties($class, $definition); + } - // Browse the object's methods looking for annotated methods - $this->readMethods($class, $definition); + // Browse the object's methods looking for annotated methods + if ($this->flags & self::METHODS) { + $this->readMethods($class, $definition); + } + } + + // constructor parameters should always be read, even if annotations are disabled (completely or i.a. for methods) + // so that it behaves at least as ReflectionBasedAutowiring + if (!$useAnnotations || !($this->flags & self::METHODS)) { + $class = $class ?? new ReflectionClass($className); + $this->readConstructor($class, $definition); + } return $definition; } @@ -260,4 +297,26 @@ private function readInjectableAttribute(ReflectionClass $class, ObjectDefinitio $definition->setLazy($attribute->isLazy()); } } + + /** + * Browse the object's constructor parameters and inject dependencies. + */ + private function readConstructor(ReflectionClass $class, ObjectDefinition $definition) + { + if (!($constructor = $class->getConstructor()) || !$constructor->isPublic()) { + return; + } + + $parameters = []; + foreach ($constructor->getParameters() as $index => $parameter) { + $entryName = $this->getMethodParameter($index, $parameter, []); + + if ($entryName !== null) { + $parameters[$index] = new Reference($entryName); + } + } + + $constructorInjection = MethodInjection::constructor($parameters); + $definition->completeConstructorInjection($constructorInjection); + } } From 55a5e10bc31c6804932888a526c949debeb6da11 Mon Sep 17 00:00:00 2001 From: Michal Kruczek Date: Mon, 16 Jan 2023 14:11:03 +0100 Subject: [PATCH 3/3] porting AnnotationBasedAutowiring for php-di v7 --- src/ContainerBuilder.php | 6 +-- src/Definition/AutowireDefinition.php | 19 +++----- .../Helper/AutowireDefinitionHelper.php | 17 ++++--- .../Source/AttributeBasedAutowiring.php | 48 +++++++++---------- 4 files changed, 41 insertions(+), 49 deletions(-) diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index d3a4a348..5693f4c6 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -52,9 +52,7 @@ class ContainerBuilder private bool $useAutowiring = true; - private int $annotationsFlags = 0; - - private bool $ignorePhpDocErrors = false; + private int $attributesFlags = 0; private bool $useAttributes = false; @@ -225,7 +223,7 @@ public function useAttributes(bool $bool, int $flags = 0) : self $this->ensureNotLocked(); $this->useAttributes = $bool; - $this->annotationsFlags = $flags; + $this->attributesFlags = $flags; return $this; } diff --git a/src/Definition/AutowireDefinition.php b/src/Definition/AutowireDefinition.php index 6bd75331..a1f46c50 100644 --- a/src/Definition/AutowireDefinition.php +++ b/src/Definition/AutowireDefinition.php @@ -9,26 +9,21 @@ */ class AutowireDefinition extends ObjectDefinition { - /** - * @var bool|null - */ - protected $useAnnotations; + protected ?bool $useAttributes; /** - * Enable/disable reading annotations for this definition, regardless of a container configuration. - * @param bool $flag + * Enable/disable reading attributes for this definition, regardless of a container configuration. */ - public function useAnnotations(bool $flag = true) + public function useAttributes(bool $flag = true) : void { - $this->useAnnotations = $flag; + $this->useAttributes = $flag; } /** - * Returns boolean if the useAnnotation flag was explicitly set, otherwise null. - * @return bool|null + * Returns boolean if the useAttributes flag was explicitly set, otherwise null. */ - public function isUsingAnnotations() + public function isUsingAttributes() : ?bool { - return $this->useAnnotations; + return $this->useAttributes; } } diff --git a/src/Definition/Helper/AutowireDefinitionHelper.php b/src/Definition/Helper/AutowireDefinitionHelper.php index 7c677538..77c70d85 100644 --- a/src/Definition/Helper/AutowireDefinitionHelper.php +++ b/src/Definition/Helper/AutowireDefinitionHelper.php @@ -5,7 +5,7 @@ namespace DI\Definition\Helper; use DI\Definition\AutowireDefinition; -use DI\Definition\Definition; +use DI\Definition\ObjectDefinition; /** * Helps defining how to create an instance of a class using autowiring. @@ -16,7 +16,7 @@ class AutowireDefinitionHelper extends CreateDefinitionHelper { public const DEFINITION_CLASS = AutowireDefinition::class; - protected $useAnnotations; + protected ?bool $useAttributes = true; /** * Defines a value for a specific argument of the constructor. @@ -74,14 +74,13 @@ public function methodParameter(string $method, string|int $parameter, mixed $va } /** - * Define if entry should use annotation reader for reading dependencies. + * Define if entry should use attributes reader for reading dependencies. * This is turned off by default if autowire() helper is used, and turned on if entry is not defined explicitly in the di config. - * @param bool $useAnnotations * @return $this */ - public function useAnnotations(bool $useAnnotations = true) + public function useAttributes(bool $useAttributes = true) : self { - $this->useAnnotations = $useAnnotations; + $this->useAttributes = $useAttributes; return $this; } @@ -89,12 +88,12 @@ public function useAnnotations(bool $useAnnotations = true) /** * @return AutowireDefinition */ - public function getDefinition(string $entryName) : Definition + public function getDefinition(string $entryName) : ObjectDefinition { /** @var AutowireDefinition $definition */ $definition = parent::getDefinition($entryName); - if ($this->useAnnotations !== null) { - $definition->useAnnotations($this->useAnnotations); + if ($this->useAttributes !== null) { + $definition->useAttributes($this->useAttributes); } return $definition; diff --git a/src/Definition/Source/AttributeBasedAutowiring.php b/src/Definition/Source/AttributeBasedAutowiring.php index 0a7eacf1..d3c90b40 100644 --- a/src/Definition/Source/AttributeBasedAutowiring.php +++ b/src/Definition/Source/AttributeBasedAutowiring.php @@ -31,17 +31,17 @@ class AttributeBasedAutowiring implements DefinitionSource, Autowiring { // Annotations configuration flags: // enable on implicit definitions - const IMPLICIT = 1; + public const IMPLICIT = 1; // enable on all autowire definitions (which are written in DI config) by default - const EXPLICIT = 2; + public const EXPLICIT = 2; // read @Injectable annotations for classes - const INJECTABLE = 4; + public const INJECTABLE = 4; // read @Inject annotations for properties - const PROPERTIES = 8; + public const PROPERTIES = 8; // read @Inject annotations for methods' parameters - const METHODS = 16; + public const METHODS = 16; // all options enabled - const ALL = 31; + public const ALL = 31; public function __construct(private int $flags = 0) { @@ -57,17 +57,17 @@ public function autowire(string $name, ObjectDefinition $definition = null) : Ob } $definition = $definition ?: new ObjectDefinition($name); - $useAnnotations = $definition instanceof AutowireDefinition - ? ($definition->isUsingAnnotations() ?? ($this->flags & self::EXPLICIT)) - : ($this->flags & self::IMPLICIT); + $useAttributes = $definition instanceof AutowireDefinition + ? ($definition->isUsingAttributes() ?? (bool) ($this->flags & self::EXPLICIT)) + : (bool) ($this->flags & self::IMPLICIT); $class = null; - if ($useAnnotations && $this->flags >= self::INJECTABLE) { + if ($useAttributes && $this->flags >= self::INJECTABLE) { $class = new ReflectionClass($className); - $this->readInjectableAttribute($class, $definition); + $this->readInjectableAttribute($class, $definition); if ($this->flags & self::INJECTABLE) { - $this->readInjectableAnnotation($class, $definition); + $this->readInjectableAttribute($class, $definition); } // Browse the class properties looking for annotated properties @@ -83,8 +83,8 @@ public function autowire(string $name, ObjectDefinition $definition = null) : Ob // constructor parameters should always be read, even if annotations are disabled (completely or i.a. for methods) // so that it behaves at least as ReflectionBasedAutowiring - if (!$useAnnotations || !($this->flags & self::METHODS)) { - $class = $class ?? new ReflectionClass($className); + if (!$useAttributes || !($this->flags & self::METHODS)) { + $class ??= new ReflectionClass($className); $this->readConstructor($class, $definition); } @@ -109,7 +109,7 @@ public function getDefinitions() : array } /** - * Browse the class properties looking for annotated properties. + * Browse the class properties looking for properties with attributes. */ private function readProperties(ReflectionClass $class, ObjectDefinition $definition) : void { @@ -182,7 +182,7 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de } /** - * Browse the object's methods looking for annotated methods. + * Browse the object's methods looking for methods with attributes. */ private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition) : void { @@ -214,17 +214,17 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection if ($attribute) { /** @var Inject $inject */ $inject = $attribute->newInstance(); - $annotationParameters = $inject->getParameters(); + $attributeParameters = $inject->getParameters(); } elseif ($method->isConstructor()) { // #[Inject] on constructor is implicit, we continue - $annotationParameters = []; + $attributeParameters = []; } else { return null; } $parameters = []; foreach ($method->getParameters() as $index => $parameter) { - $entryName = $this->getMethodParameter($index, $parameter, $annotationParameters); + $entryName = $this->getMethodParameter($index, $parameter, $attributeParameters); if ($entryName !== null) { $parameters[$index] = new Reference($entryName); @@ -241,7 +241,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 + private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $attributeParameters) : ?string { // Let's check if this parameter has an #[Inject] attribute $attribute = $parameter->getAttributes(Inject::class)[0] ?? null; @@ -253,11 +253,11 @@ private function getMethodParameter(int $parameterIndex, ReflectionParameter $pa } // #[Inject] has definition for this parameter (by index, or by name) - if (isset($annotationParameters[$parameterIndex])) { - return $annotationParameters[$parameterIndex]; + if (isset($attributeParameters[$parameterIndex])) { + return $attributeParameters[$parameterIndex]; } - if (isset($annotationParameters[$parameter->getName()])) { - return $annotationParameters[$parameter->getName()]; + if (isset($attributeParameters[$parameter->getName()])) { + return $attributeParameters[$parameter->getName()]; } // Skip optional parameters if not explicitly defined