Skip to content

Commit 59a2216

Browse files
committed
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
1 parent 65987ec commit 59a2216

File tree

4 files changed

+129
-9
lines changed

4 files changed

+129
-9
lines changed

src/ContainerBuilder.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ class ContainerBuilder
5656
*/
5757
private $useAnnotations = false;
5858

59+
/**
60+
* @var int
61+
*/
62+
private $annotationsFlags = 0;
63+
5964
/**
6065
* @var bool
6166
*/
@@ -126,7 +131,7 @@ public function build()
126131
$sources = array_reverse($this->definitionSources);
127132

128133
if ($this->useAnnotations) {
129-
$autowiring = new AnnotationBasedAutowiring($this->ignorePhpDocErrors);
134+
$autowiring = new AnnotationBasedAutowiring($this->ignorePhpDocErrors, $this->annotationsFlags);
130135
$sources[] = $autowiring;
131136
} elseif ($this->useAutowiring) {
132137
$autowiring = new ReflectionBasedAutowiring;
@@ -239,11 +244,12 @@ public function useAutowiring(bool $bool) : self
239244
*
240245
* @return $this
241246
*/
242-
public function useAnnotations(bool $bool) : self
247+
public function useAnnotations(bool $bool, int $flags = 0) : self
243248
{
244249
$this->ensureNotLocked();
245250

246251
$this->useAnnotations = $bool;
252+
$this->annotationsFlags = $flags;
247253

248254
return $this;
249255
}

src/Definition/AutowireDefinition.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,26 @@
99
*/
1010
class AutowireDefinition extends ObjectDefinition
1111
{
12+
/**
13+
* @var bool|null
14+
*/
15+
protected $useAnnotations;
16+
17+
/**
18+
* Enable/disable reading annotations for this definition, regardless of a container configuration.
19+
* @param bool $flag
20+
*/
21+
public function useAnnotations(bool $flag = true)
22+
{
23+
$this->useAnnotations = $flag;
24+
}
25+
26+
/**
27+
* Returns boolean if the useAnnotation flag was explicitly set, otherwise null.
28+
* @return bool|null
29+
*/
30+
public function isUsingAnnotations()
31+
{
32+
return $this->useAnnotations;
33+
}
1234
}

src/Definition/Helper/AutowireDefinitionHelper.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace DI\Definition\Helper;
66

77
use DI\Definition\AutowireDefinition;
8+
use DI\Definition\Definition;
89

910
/**
1011
* Helps defining how to create an instance of a class using autowiring.
@@ -15,6 +16,8 @@ class AutowireDefinitionHelper extends CreateDefinitionHelper
1516
{
1617
const DEFINITION_CLASS = AutowireDefinition::class;
1718

19+
protected $useAnnotations;
20+
1821
/**
1922
* Defines a value for a specific argument of the constructor.
2023
*
@@ -69,4 +72,31 @@ public function methodParameter(string $method, $parameter, $value)
6972

7073
return $this;
7174
}
75+
76+
/**
77+
* Define if entry should use annotation reader for reading dependencies.
78+
* This is turned off by default if autowire() helper is used, and turned on if entry is not defined explicitly in the di config.
79+
* @param bool $useAnnotations
80+
* @return $this
81+
*/
82+
public function useAnnotations(bool $useAnnotations = true)
83+
{
84+
$this->useAnnotations = $useAnnotations;
85+
86+
return $this;
87+
}
88+
89+
/**
90+
* @return AutowireDefinition
91+
*/
92+
public function getDefinition(string $entryName) : Definition
93+
{
94+
/** @var AutowireDefinition $definition */
95+
$definition = parent::getDefinition($entryName);
96+
if ($this->useAnnotations !== null) {
97+
$definition->useAnnotations($this->useAnnotations);
98+
}
99+
100+
return $definition;
101+
}
72102
}

src/Definition/Source/AnnotationBasedAutowiring.php

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use DI\Annotation\Inject;
88
use DI\Annotation\Injectable;
9+
use DI\Definition\AutowireDefinition;
910
use DI\Definition\Exception\InvalidAnnotation;
1011
use DI\Definition\ObjectDefinition;
1112
use DI\Definition\ObjectDefinition\MethodInjection;
@@ -32,6 +33,25 @@
3233
*/
3334
class AnnotationBasedAutowiring implements DefinitionSource, Autowiring
3435
{
36+
// Annotations configuration flags:
37+
// enable on implicit definitions
38+
const IMPLICIT = 1;
39+
// enable on all autowire definitions (which are written in DI config) by default
40+
const EXPLICIT = 2;
41+
// read @Injectable annotations for classes
42+
const INJECTABLE = 4;
43+
// read @Inject annotations for properties
44+
const PROPERTIES = 8;
45+
// read @Inject annotations for methods' parameters
46+
const METHODS = 16;
47+
// all options enabled
48+
const ALL = 31;
49+
50+
/**
51+
* @var int
52+
*/
53+
private $flags;
54+
3555
/**
3656
* @var Reader
3757
*/
@@ -47,9 +67,10 @@ class AnnotationBasedAutowiring implements DefinitionSource, Autowiring
4767
*/
4868
private $ignorePhpDocErrors;
4969

50-
public function __construct($ignorePhpDocErrors = false)
70+
public function __construct($ignorePhpDocErrors = false, int $flags = 0)
5171
{
5272
$this->ignorePhpDocErrors = (bool) $ignorePhpDocErrors;
73+
$this->flags = $flags > 0 ? $flags : self::ALL; // all flags turned on by default
5374
}
5475

5576
public function autowire(string $name, ObjectDefinition $definition = null)
@@ -61,16 +82,35 @@ public function autowire(string $name, ObjectDefinition $definition = null)
6182
}
6283

6384
$definition = $definition ?: new ObjectDefinition($name);
85+
$useAnnotations = $definition instanceof AutowireDefinition
86+
? ($definition->isUsingAnnotations() ?? ($this->flags & self::EXPLICIT))
87+
: ($this->flags & self::IMPLICIT);
6488

65-
$class = new ReflectionClass($className);
89+
$class = null;
90+
if ($useAnnotations && $this->flags >= self::INJECTABLE) {
91+
$class = new ReflectionClass($className);
6692

67-
$this->readInjectableAnnotation($class, $definition);
93+
if ($this->flags & self::INJECTABLE) {
94+
$this->readInjectableAnnotation($class, $definition);
95+
}
6896

69-
// Browse the class properties looking for annotated properties
70-
$this->readProperties($class, $definition);
97+
// Browse the class properties looking for annotated properties
98+
if ($this->flags & self::PROPERTIES) {
99+
$this->readProperties($class, $definition);
100+
}
71101

72-
// Browse the object's methods looking for annotated methods
73-
$this->readMethods($class, $definition);
102+
// Browse the object's methods looking for annotated methods
103+
if ($this->flags & self::METHODS) {
104+
$this->readMethods($class, $definition);
105+
}
106+
}
107+
108+
// constructor parameters should always be read, even if annotations are disabled (completely or i.a. for methods)
109+
// so that it behaves at least as ReflectionBasedAutowiring
110+
if (!$useAnnotations || !($this->flags & self::METHODS)) {
111+
$class = $class ?? new ReflectionClass($className);
112+
$this->readConstructor($class, $definition);
113+
}
74114

75115
return $definition;
76116
}
@@ -166,6 +206,28 @@ private function readMethods(ReflectionClass $class, ObjectDefinition $objectDef
166206
}
167207
}
168208

209+
/**
210+
* Browse the object's constructor parameters and inject dependencies.
211+
*/
212+
private function readConstructor(ReflectionClass $class, ObjectDefinition $definition)
213+
{
214+
if (!($constructor = $class->getConstructor()) || !$constructor->isPublic()) {
215+
return;
216+
}
217+
218+
$parameters = [];
219+
foreach ($constructor->getParameters() as $index => $parameter) {
220+
$entryName = $this->getMethodParameter($index, $parameter, []);
221+
222+
if ($entryName !== null) {
223+
$parameters[$index] = new Reference($entryName);
224+
}
225+
}
226+
227+
$constructorInjection = MethodInjection::constructor($parameters);
228+
$definition->completeConstructorInjection($constructorInjection);
229+
}
230+
169231
/**
170232
* @param ReflectionMethod $method
171233
*

0 commit comments

Comments
 (0)