This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php declare(strict_types = 1); |
||
2 | /** |
||
3 | * Created by PhpStorm. |
||
4 | * User: root |
||
5 | * Date: 02.08.16 |
||
6 | * Time: 0:46. |
||
7 | */ |
||
8 | namespace samsonframework\container; |
||
9 | |||
10 | use samsonframework\container\ContainerInterface; |
||
11 | use samsonframework\container\metadata\ClassMetadata; |
||
12 | use samsonframework\container\metadata\MethodMetadata; |
||
13 | use samsonframework\container\metadata\PropertyMetadata; |
||
14 | use samsonframework\di\Container; |
||
15 | use samsonphp\generator\Generator; |
||
16 | |||
17 | /** |
||
18 | * Container builder. |
||
19 | * |
||
20 | * @author Vitaly Egorov <[email protected]> |
||
21 | */ |
||
22 | class Builder implements ContainerBuilderInterface |
||
23 | { |
||
24 | /** Controller classes scope name */ |
||
25 | const SCOPE_CONTROLLER = 'controllers'; |
||
26 | |||
27 | /** Service classes scope name */ |
||
28 | const SCOPE_SERVICES = 'service'; |
||
29 | |||
30 | /** Generated resolving function name prefix */ |
||
31 | const DI_FUNCTION_PREFIX = 'container'; |
||
32 | |||
33 | /** Generated resolving function service static collection name */ |
||
34 | const DI_FUNCTION_SERVICES = self::SCOPE_SERVICES . 'Instances'; |
||
35 | |||
36 | /** @var string[] Collection of available container scopes */ |
||
37 | protected $scopes = [ |
||
38 | self::SCOPE_CONTROLLER => [], |
||
39 | self::SCOPE_SERVICES => [] |
||
40 | ]; |
||
41 | |||
42 | /** @var ClassMetadata[] Collection of classes metadata */ |
||
43 | protected $classesMetadata = []; |
||
44 | |||
45 | /** @var array Collection of dependencies aliases */ |
||
46 | protected $classAliases = []; |
||
47 | |||
48 | /** @var ContainerInterface */ |
||
49 | protected $parentContainer; |
||
50 | |||
51 | /** |
||
52 | * @var Generator |
||
53 | */ |
||
54 | protected $generator; |
||
55 | |||
56 | /** @var string Resolver function name */ |
||
57 | protected $resolverFunction; |
||
58 | |||
59 | /** |
||
60 | * Container builder constructor. |
||
61 | * |
||
62 | * @param Generator $generator PHP code generator |
||
63 | * @param ClassMetadata[] $classMetadata Collection of classes metadata for container |
||
0 ignored issues
–
show
|
|||
64 | */ |
||
65 | public function __construct(Generator $generator) |
||
66 | { |
||
67 | $this->generator = $generator; |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * {@inheritdoc} |
||
72 | */ |
||
73 | public function build(array $classesMetadata, $containerClass = 'Container', $namespace = '', ContainerInterface $parentContainer = null) |
||
74 | { |
||
75 | $this->classesMetadata = $this->processClassMetadata($classesMetadata); |
||
76 | $this->parentContainer = $parentContainer; |
||
77 | |||
78 | // Build dependency injection container function name |
||
79 | $this->resolverFunction = uniqid(self::DI_FUNCTION_PREFIX); |
||
80 | |||
81 | $containerDependencies = []; |
||
82 | foreach ($classesMetadata as $classMetadata) { |
||
83 | $className = $classMetadata->className; |
||
84 | // Store inner dependencies |
||
85 | if (array_key_exists('__construct', $classMetadata->methodsMetadata)) { |
||
86 | $containerDependencies[$className] = array_values($classMetadata->methodsMetadata['__construct']->dependencies ?? []); |
||
87 | } |
||
88 | } |
||
89 | |||
90 | $this->generator |
||
91 | ->text('<?php declare(strict_types = 1);') |
||
92 | ->newLine() |
||
93 | ->defNamespace($namespace) |
||
94 | ->multiComment(['Application container']) |
||
95 | ->defClass($containerClass, '\\' . Container::class) |
||
96 | ->multiComment(['@var array Collection of service instances']) |
||
97 | ->defClassFunction('__construct', 'public', [], ['Container constructor']) |
||
98 | ->newLine('$this->dependencies = ')->arrayValue($containerDependencies)->text(';') |
||
99 | ->newLine('$this->aliases = ')->arrayValue($this->classAliases)->text(';') |
||
100 | ->newLine('$this->scopes = ')->arrayValue($this->scopes)->text(';') |
||
101 | ->newLine('$this->services = ')->arrayValue($this->scopes[self::SCOPE_SERVICES])->text(';') |
||
102 | ->endClassFunction() |
||
103 | ->defClassFunction('logic', 'protected', ['$dependency'], ['{@inheritdoc}']) |
||
104 | ->newLine('return $this->' . $this->resolverFunction . '($dependency);') |
||
105 | ->endClassFunction(); |
||
106 | |||
107 | foreach ($this->classesMetadata as $classMetadata) { |
||
108 | $className = $classMetadata->className; |
||
109 | $dependencyName = $classMetadata->name ?? $className; |
||
110 | |||
111 | // Generate camel case getter method |
||
112 | $camelMethodName = 'get' . str_replace(' ', '', ucwords(ucfirst(str_replace(['\\', '_'], ' ', $dependencyName)))); |
||
113 | |||
114 | $this->generator |
||
115 | ->defClassFunction($camelMethodName, 'public', [], ['@return ' . '\\'.ltrim($className, '\\') . ' Get ' . $dependencyName . ' instance']) |
||
116 | ->newLine('return $this->' . $this->resolverFunction . '(\'' . $dependencyName . '\');') |
||
117 | ->endClassFunction(); |
||
118 | } |
||
119 | |||
120 | // Build di container function and add to container class and return class code |
||
121 | $this->buildDependencyResolver($this->resolverFunction); |
||
122 | |||
123 | return $this->generator |
||
124 | ->endClass() |
||
125 | ->flush(); |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * Read class metadata and fill internal collections. |
||
130 | * |
||
131 | * @param ClassMetadata[] $classesMetadata |
||
132 | * @return ClassMetadata[] Processed class metadata |
||
133 | */ |
||
134 | public function processClassMetadata(array $classesMetadata) : array |
||
135 | { |
||
136 | /** @var ClassMetadata[] $processedClassesMetadata */ |
||
137 | $processedClassesMetadata = []; |
||
138 | |||
139 | // Read all classes in given file |
||
140 | foreach ($classesMetadata as $classMetadata) { |
||
141 | // Store by metadata name as alias |
||
142 | $this->classAliases[$classMetadata->className] = $classMetadata->name; |
||
143 | |||
144 | // Store class in defined scopes |
||
145 | foreach ($classMetadata->scopes as $scope) { |
||
146 | $this->scopes[$scope][$classMetadata->name] = $classMetadata->className; |
||
147 | } |
||
148 | $processedClassesMetadata[$classMetadata->name] = $classMetadata; |
||
149 | } |
||
150 | |||
151 | $dependencies = []; |
||
152 | foreach ($processedClassesMetadata as $alias => $classMetadata) { |
||
153 | if (count($classMetadata->methodsMetadata)) { |
||
154 | foreach ($classMetadata->methodsMetadata as $methodMetadata) { |
||
155 | foreach ($methodMetadata->dependencies as $dependency) { |
||
156 | if (in_array($this->getArgumentType($dependency), [1, 2], true)) { |
||
157 | $dependencies[] = $dependency; |
||
158 | } |
||
159 | } |
||
160 | } |
||
161 | $dependencies[] = $classMetadata->name; |
||
162 | } |
||
163 | if (count($classMetadata->propertiesMetadata)) { |
||
164 | foreach ($classMetadata->propertiesMetadata as $propertyMetadata) { |
||
165 | $dependencies[] = $propertyMetadata->dependency; |
||
166 | } |
||
167 | $dependencies[] = $classMetadata->name; |
||
168 | } |
||
169 | if (count($classMetadata->scopes)) { |
||
170 | $dependencies[] = $classMetadata->name; |
||
171 | } |
||
172 | } |
||
173 | $dependencies = array_unique($dependencies); |
||
174 | |||
175 | foreach ($processedClassesMetadata as $alias => $classMetadata) { |
||
176 | if (!in_array($alias, $dependencies, true)) { |
||
177 | unset($processedClassesMetadata[$alias]); |
||
178 | } |
||
179 | } |
||
180 | $this->generator->flush(); |
||
181 | |||
182 | return $processedClassesMetadata; |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Build dependency resolving function. |
||
187 | * |
||
188 | * @param string $functionName Function name |
||
189 | * |
||
190 | * @throws \InvalidArgumentException |
||
191 | */ |
||
192 | protected function buildDependencyResolver($functionName) |
||
193 | { |
||
194 | $inputVariable = '$aliasOrClassName'; |
||
195 | $this->generator |
||
196 | ->defClassFunction($functionName, 'protected', [$inputVariable], ['Dependency resolving function']) |
||
197 | //->defVar('static ' . self::DI_FUNCTION_SERVICES . ' = []') |
||
198 | ->newLine(); |
||
199 | |||
200 | // Generate all container and delegate conditions |
||
201 | $this->generateConditions($inputVariable, false); |
||
202 | |||
203 | // Add method not found |
||
204 | $this->generator->endIfCondition()->endFunction(); |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Generate logic conditions and their implementation for container and its delegates. |
||
209 | * |
||
210 | * @param string $inputVariable Input condition parameter variable name |
||
211 | * @param bool|false $started Flag if condition branching has been started |
||
212 | */ |
||
213 | public function generateConditions($inputVariable = '$alias', $started = false) |
||
214 | { |
||
215 | // Iterate all container dependencies |
||
216 | foreach ($this->classesMetadata as $classMetadata) { |
||
217 | $className = $classMetadata->className; |
||
218 | // Generate condition statement to define if this class is needed |
||
219 | $conditionFunc = !$started ? 'defIfCondition' : 'defElseIfCondition'; |
||
220 | |||
221 | // Output condition branch |
||
222 | $this->generator->$conditionFunc( |
||
223 | $this->buildResolverCondition($inputVariable, $className, $classMetadata->name) |
||
224 | ); |
||
225 | |||
226 | // Define if this class has service scope |
||
227 | $isService = in_array($className, $this->scopes[self::SCOPE_SERVICES], true); |
||
228 | |||
229 | /** @var MethodMetadata[] Gather only valid method for container */ |
||
230 | $classValidMethods = $this->getValidClassMethodsMetadata($classMetadata->methodsMetadata); |
||
231 | |||
232 | /** @var PropertyMetadata[] Gather only valid property for container */ |
||
233 | $classValidProperties = $this->getValidClassPropertiesMetadata($classMetadata->propertiesMetadata); |
||
234 | |||
235 | // Define class or service variable |
||
236 | $staticContainerName = $isService |
||
237 | ? '$this->' . self::DI_FUNCTION_SERVICES . '[\'' . $classMetadata->name . '\']' |
||
238 | : '$temp'; |
||
239 | |||
240 | if ($isService) { |
||
241 | // Check if dependency was instantiated |
||
242 | $this->generator->defIfCondition('!array_key_exists(\'' . $classMetadata->name . '\', $this->' . self::DI_FUNCTION_SERVICES . ')'); |
||
243 | } |
||
244 | |||
245 | if (count($classValidMethods) || count($classValidProperties)) { |
||
246 | $this->generator->newLine($staticContainerName . ' = '); |
||
247 | $this->buildResolvingClassDeclaration($className); |
||
248 | $this->buildConstructorDependencies($classMetadata->methodsMetadata); |
||
249 | |||
250 | // Internal scope reflection variable |
||
251 | $reflectionVariable = '$reflectionClass'; |
||
252 | |||
253 | $this->buildReflectionClass($className, $classValidProperties, $classValidMethods, $reflectionVariable); |
||
254 | |||
255 | // Process class properties |
||
256 | foreach ($classValidProperties as $property) { |
||
257 | // If such property has the dependency |
||
258 | if ($property->dependency) { |
||
259 | // Set value via refection |
||
260 | $this->buildResolverPropertyDeclaration( |
||
261 | $property->name, |
||
262 | $property->dependency, |
||
263 | $staticContainerName, |
||
264 | $reflectionVariable, |
||
265 | $property->isPublic |
||
266 | ); |
||
267 | } |
||
268 | } |
||
269 | |||
270 | /** @var MethodMetadata $methodMetadata */ |
||
271 | foreach ($classValidMethods as $methodName => $methodMetadata) { |
||
272 | $this->buildResolverMethodDeclaration( |
||
273 | $methodMetadata->dependencies, |
||
274 | $methodName, |
||
275 | $staticContainerName, |
||
276 | $reflectionVariable, |
||
277 | $methodMetadata->isPublic |
||
278 | ); |
||
279 | } |
||
280 | |||
281 | if ($isService) { |
||
282 | $this->generator->endIfCondition(); |
||
283 | } |
||
284 | |||
285 | $this->generator->newLine()->newLine('return ' . $staticContainerName . ';'); |
||
286 | } else { |
||
287 | if ($isService) { |
||
288 | $this->generator->newLine($staticContainerName.' = '); |
||
289 | $this->buildResolvingClassDeclaration($className); |
||
290 | $this->buildConstructorDependencies($classMetadata->methodsMetadata); |
||
291 | $this->generator->endIfCondition()->newLine('return ' . $staticContainerName . ';'); |
||
292 | } else { |
||
293 | $this->generator->newLine('return '); |
||
294 | $this->buildResolvingClassDeclaration($className); |
||
295 | $this->buildConstructorDependencies($classMetadata->methodsMetadata); |
||
296 | } |
||
297 | |||
0 ignored issues
–
show
|
|||
298 | } |
||
299 | |||
300 | // Set flag that condition is started |
||
301 | $started = true; |
||
302 | } |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * Build resolving function condition. |
||
307 | * |
||
308 | * @param string $inputVariable Condition variable |
||
309 | * @param string $className |
||
310 | * @param string|null $alias |
||
311 | * |
||
312 | * @return string Condition code |
||
313 | */ |
||
314 | protected function buildResolverCondition(string $inputVariable, string $className, string $alias = null) : string |
||
315 | { |
||
316 | // Create condition branch |
||
317 | $condition = $inputVariable . ' === \'' . $className . '\''; |
||
318 | |||
319 | if ($alias !== null && $alias !== $className) { |
||
320 | $condition .= '||' . $this->buildResolverCondition($inputVariable, $alias); |
||
321 | } |
||
322 | |||
323 | return $condition; |
||
324 | } |
||
325 | |||
326 | /** |
||
327 | * Get valid class methods metadata. |
||
328 | * |
||
329 | * @param MethodMetadata[] $classMethodsMetadata All class methods metadata |
||
330 | * |
||
331 | * @return array Valid class methods metadata |
||
332 | */ |
||
333 | protected function getValidClassMethodsMetadata(array $classMethodsMetadata) |
||
334 | { |
||
335 | /** @var MethodMetadata[] Gather only valid method for container */ |
||
336 | $classValidMethods = []; |
||
337 | foreach ($classMethodsMetadata as $methodName => $methodMetadata) { |
||
338 | // Skip constructor method and empty dependencies |
||
339 | if ($methodName !== '__construct' && count($methodMetadata->dependencies) > 0) { |
||
0 ignored issues
–
show
|
|||
340 | $classValidMethods[$methodName] = $methodMetadata; |
||
341 | } |
||
342 | } |
||
343 | |||
344 | return $classValidMethods; |
||
345 | } |
||
346 | |||
347 | /** |
||
348 | * Get valid class properties metadata. |
||
349 | * |
||
350 | * @param PropertyMetadata[] $classPropertiesMetadata All class properties metadata |
||
351 | * |
||
352 | * @return array Valid class properties metadata |
||
353 | */ |
||
354 | protected function getValidClassPropertiesMetadata(array $classPropertiesMetadata) |
||
355 | { |
||
356 | /** @var PropertyMetadata[] Gather only valid property for container */ |
||
357 | $classValidProperties = []; |
||
358 | foreach ($classPropertiesMetadata as $propertyName => $propertyMetadata) { |
||
359 | // Skip constructor method and empty dependencies |
||
360 | if ($propertyMetadata->dependency) { |
||
361 | $classValidProperties[$propertyName] = $propertyMetadata; |
||
362 | } |
||
363 | } |
||
364 | |||
365 | return $classValidProperties; |
||
366 | } |
||
367 | |||
368 | /** |
||
369 | * Build resolving function class block. |
||
370 | * |
||
371 | * @param string $className Class name for new instance creation |
||
372 | */ |
||
373 | protected function buildResolvingClassDeclaration(string $className) |
||
374 | { |
||
375 | $this->generator->text('new \\' . ltrim($className, '\\') . '('); |
||
376 | } |
||
377 | |||
378 | /** |
||
379 | * Build constructor arguments injection. |
||
380 | * |
||
381 | * @param MethodMetadata[] $methodsMetaData |
||
382 | */ |
||
383 | protected function buildConstructorDependencies(array $methodsMetaData) |
||
384 | { |
||
385 | // Process constructor dependencies |
||
386 | $argumentsCount = 0; |
||
387 | if (array_key_exists('__construct', $methodsMetaData)) { |
||
388 | $constructorArguments = $methodsMetaData['__construct']->dependencies ?? []; |
||
389 | $argumentsCount = count($constructorArguments); |
||
390 | $i = 0; |
||
391 | |||
392 | // Add indentation to move declaration arguments |
||
393 | $this->generator->tabs++; |
||
394 | |||
395 | if ($methodsMetaData['__construct'] && isset($methodsMetaData['__construct']->classMetadata)) { |
||
396 | $className = $methodsMetaData['__construct']->classMetadata->className; |
||
397 | $parameters = (new \ReflectionMethod($className, '__construct'))->getParameters(); |
||
398 | foreach ($parameters as $parameter) { |
||
399 | if (isset($constructorArguments[$parameter->getName()])) { |
||
0 ignored issues
–
show
![]() |
|||
400 | $this->buildResolverArgument($constructorArguments[$parameter->getName()]); |
||
0 ignored issues
–
show
![]() |
|||
401 | // Add comma if this is not last dependency |
||
402 | if (++$i < $argumentsCount) { |
||
403 | $this->generator->text(','); |
||
404 | } |
||
405 | } |
||
406 | } |
||
407 | } |
||
408 | |||
409 | // Process constructor arguments |
||
410 | // foreach ($constructorArguments as $argument => $parameterMetadata) { |
||
411 | // $this->buildResolverArgument($parameterMetadata); |
||
412 | // |
||
413 | // // Add comma if this is not last dependency |
||
414 | // if (++$i < $argumentsCount) { |
||
415 | // $this->generator->text(','); |
||
416 | // } |
||
417 | // } |
||
418 | |||
419 | // Restore indentation |
||
420 | $this->generator->tabs--; |
||
421 | } |
||
422 | |||
423 | // Close declaration block, multiline if we have dependencies |
||
424 | $argumentsCount ? $this->generator->newLine(');') : $this->generator->text(');'); |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * Build resolving function dependency argument. |
||
429 | * |
||
430 | * @param mixed $argument Dependency argument |
||
431 | * |
||
432 | * @throws \InvalidArgumentException On invalid argument type |
||
433 | */ |
||
434 | protected function buildResolverArgument($argument, $textFunction = 'newLine') |
||
435 | { |
||
436 | switch ($this->getArgumentType($argument)) { |
||
437 | // Call container logic for this dependency |
||
438 | case 1: |
||
0 ignored issues
–
show
case statements should be defined using a colon.
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces.
There is no need for braces, since each case is terminated by the next There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages. switch ($expr) {
case "A": { //wrong
doSomething();
break;
}
case "B"; //wrong
doSomething();
break;
case "C": //right
doSomething();
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
439 | return $this->generator->$textFunction('$this->get(\'' . $argument . '\')'); |
||
440 | // Call container logic for this dependency by alias |
||
441 | case 2: |
||
0 ignored issues
–
show
case statements should be defined using a colon.
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces.
There is no need for braces, since each case is terminated by the next There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages. switch ($expr) {
case "A": { //wrong
doSomething();
break;
}
case "B"; //wrong
doSomething();
break;
case "C": //right
doSomething();
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
442 | return $this->generator->$textFunction('$this->get(\'' . $this->classAliases[$argument] . '\')'); |
||
443 | // String variable |
||
444 | case 3: |
||
0 ignored issues
–
show
case statements should be defined using a colon.
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces.
There is no need for braces, since each case is terminated by the next There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages. switch ($expr) {
case "A": { //wrong
doSomething();
break;
}
case "B"; //wrong
doSomething();
break;
case "C": //right
doSomething();
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
445 | return $this->generator->$textFunction()->stringValue($argument); |
||
446 | // Dependency value is array |
||
447 | case 4: |
||
0 ignored issues
–
show
case statements should be defined using a colon.
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces.
There is no need for braces, since each case is terminated by the next There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages. switch ($expr) {
case "A": { //wrong
doSomething();
break;
}
case "B"; //wrong
doSomething();
break;
case "C": //right
doSomething();
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
448 | return $this->generator->$textFunction()->arrayValue($argument); |
||
449 | } |
||
450 | } |
||
451 | |||
452 | /** |
||
453 | * Define argument type |
||
454 | * |
||
455 | * @param mixed $argument |
||
456 | * @return int |
||
457 | * @throws \InvalidArgumentException |
||
458 | */ |
||
459 | protected function getArgumentType($argument) : int |
||
460 | { |
||
461 | // This is a dependency which invokes resolving function |
||
462 | if (is_string($argument)) { |
||
463 | if ($this->parentContainer !== null && $this->parentContainer->has($argument)) { |
||
464 | return 1; |
||
465 | } elseif (array_key_exists($argument, $this->classesMetadata)) { |
||
466 | return 1; |
||
467 | } elseif (array_key_exists($argument, $this->classAliases)) { |
||
468 | return 2; |
||
469 | } elseif (class_exists($argument)) { // If this argument is existing class |
||
470 | throw new \InvalidArgumentException($argument.' class metadata is not defined'); |
||
471 | } elseif (interface_exists($argument)) { // If this argument is existing interface |
||
472 | throw new \InvalidArgumentException($argument.' - interface dependency not resolvable'); |
||
473 | } else { // String variable |
||
474 | return 3; |
||
475 | } |
||
476 | } elseif (is_array($argument)) { // Dependency value is array |
||
477 | return 4; |
||
478 | } |
||
479 | |||
480 | return 0; |
||
481 | } |
||
482 | |||
483 | /** |
||
484 | * Generate reflection class for private/protected methods or properties |
||
485 | * in current scope. |
||
486 | * |
||
487 | * @param string $className Reflection class source class name |
||
488 | * @param PropertyMetadata[] $propertiesMetadata Properties metadata |
||
489 | * @param MethodMetadata[] $methodsMetadata Methods metadata |
||
490 | * @param string $reflectionVariable Reflection class variable name |
||
491 | */ |
||
492 | protected function buildReflectionClass(string $className, array $propertiesMetadata, array $methodsMetadata, string $reflectionVariable) |
||
493 | { |
||
494 | /** |
||
495 | * Iterate all properties and create internal scope reflection class instance if |
||
496 | * at least one property in not public |
||
497 | */ |
||
498 | View Code Duplication | foreach ($propertiesMetadata as $propertyMetadata) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
499 | if (!$propertyMetadata->isPublic) { |
||
500 | $this->generator |
||
501 | ->comment('Create reflection class for injecting private/protected properties and methods') |
||
502 | ->newLine($reflectionVariable . ' = new \ReflectionClass(\'' . $className . '\');') |
||
503 | ->newLine(); |
||
504 | |||
505 | return true; |
||
506 | } |
||
507 | } |
||
508 | |||
509 | /** |
||
510 | * Iterate all properties and create internal scope reflection class instance if |
||
511 | * at least one property in not public |
||
512 | */ |
||
513 | View Code Duplication | foreach ($methodsMetadata as $methodMetadata) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
514 | if (!$methodMetadata->isPublic) { |
||
515 | $this->generator |
||
516 | ->comment('Create reflection class for injecting private/protected properties and methods') |
||
517 | ->newLine($reflectionVariable . ' = new \ReflectionClass(\'' . $className . '\');') |
||
518 | ->newLine(); |
||
519 | |||
520 | return true; |
||
521 | } |
||
522 | } |
||
523 | |||
524 | return false; |
||
525 | } |
||
526 | |||
527 | /** |
||
528 | * Build resolving property injection declaration. |
||
529 | * |
||
530 | * @param string $propertyName Target property name |
||
531 | * @param string $dependency Dependency class name |
||
532 | * @param string $containerVariable Container declaration variable name |
||
533 | * @param string $reflectionVariable Reflection class variable name |
||
534 | * @param bool $isPublic Flag if property is public |
||
535 | */ |
||
536 | protected function buildResolverPropertyDeclaration( |
||
537 | string $propertyName, |
||
538 | string $dependency, |
||
539 | string $containerVariable, |
||
540 | string $reflectionVariable, |
||
541 | bool $isPublic |
||
542 | ) |
||
543 | { |
||
0 ignored issues
–
show
|
|||
544 | if ($isPublic) { |
||
545 | $this->generator |
||
546 | ->comment('Inject public dependency for $' . $propertyName) |
||
547 | ->newLine($containerVariable . '->' . $propertyName . ' = '); |
||
548 | $this->buildResolverArgument($dependency, 'text'); |
||
549 | $this->generator->text(';'); |
||
550 | } else { |
||
551 | $this->generator |
||
552 | ->comment('Inject private dependency for $' . $propertyName) |
||
553 | ->newLine('$property = ' . $reflectionVariable . '->getProperty(\'' . $propertyName . '\');') |
||
554 | ->newLine('$property->setAccessible(true);') |
||
555 | ->newLine('$property->setValue(') |
||
556 | ->increaseIndentation() |
||
557 | ->newLine($containerVariable . ','); |
||
558 | |||
559 | $this->buildResolverArgument($dependency); |
||
560 | |||
561 | $this->generator |
||
562 | ->decreaseIndentation() |
||
563 | ->newLine(');') |
||
564 | ->newLine('$property->setAccessible(false);') |
||
565 | ->newLine(); |
||
566 | } |
||
567 | } |
||
568 | |||
569 | /** |
||
570 | * Build resolving method injection declaration. |
||
571 | * |
||
572 | * @param array $dependencies Collection of method dependencies |
||
573 | * @param string $methodName Method name |
||
574 | * @param string $containerVariable Container declaration variable name |
||
575 | * @param string $reflectionVariable Reflection class variable name |
||
576 | * @param bool $isPublic Flag if method is public |
||
577 | */ |
||
578 | protected function buildResolverMethodDeclaration( |
||
579 | array $dependencies, |
||
580 | string $methodName, |
||
581 | string $containerVariable, |
||
582 | string $reflectionVariable, |
||
583 | bool $isPublic |
||
584 | ) |
||
585 | { |
||
0 ignored issues
–
show
|
|||
586 | // Get method arguments |
||
587 | $argumentsCount = count($dependencies); |
||
588 | |||
589 | $this->generator->comment('Invoke ' . $methodName . '() and pass dependencies(y)'); |
||
590 | |||
591 | if ($isPublic) { |
||
592 | $this->generator->newLine($containerVariable . '->' . $methodName . '(')->increaseIndentation(); |
||
593 | } else { |
||
594 | $this->generator |
||
595 | ->newLine('$method = ' . $reflectionVariable . '->getMethod(\'' . $methodName . '\');') |
||
596 | ->newLine('$method->setAccessible(true);') |
||
597 | ->newLine('$method->invoke(') |
||
598 | ->increaseIndentation() |
||
599 | ->newLine($containerVariable . ','); |
||
600 | } |
||
601 | |||
602 | $i = 0; |
||
603 | // Iterate method arguments |
||
604 | foreach ($dependencies as $argument => $dependency) { |
||
605 | // Add dependencies |
||
606 | $this->buildResolverArgument($dependency); |
||
607 | |||
608 | // Add comma if this is not last dependency |
||
609 | if (++$i < $argumentsCount) { |
||
610 | $this->generator->text(','); |
||
611 | } |
||
612 | } |
||
613 | |||
614 | $this->generator->decreaseIndentation()->newLine(');'); |
||
615 | } |
||
616 | } |
||
617 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italy
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.