|
35 | 35 | use PHPStan\Type\FileTypeMapper; |
36 | 36 | use PHPStan\Type\Type; |
37 | 37 | use function array_key_exists; |
38 | | -use function array_merge; |
39 | 38 | use function count; |
40 | 39 | use function in_array; |
41 | 40 | use function is_file; |
| 41 | +use function spl_object_id; |
42 | 42 |
|
43 | 43 | #[AutowiredService] |
44 | 44 | final class DependencyResolver |
45 | 45 | { |
46 | 46 |
|
47 | | - /** @var array<string, list<ClassReflection|FunctionReflection|ConstantReflection>> */ |
| 47 | + /** @var array<string, array<int, ClassReflection|FunctionReflection|ConstantReflection>> reflections keyed by spl_object_id() */ |
48 | 48 | private array $classDependencies = []; |
49 | 49 |
|
50 | 50 | private ExportedNameScopeTracker $nameScopeTracker; |
@@ -74,6 +74,9 @@ public function resolveDependencies(Node $node, Scope $scope): NodeDependencies |
74 | 74 | } |
75 | 75 | $this->nameScopeTracker->enterNode($node); |
76 | 76 |
|
| 77 | + // Keyed by spl_object_id(), so that a reflection collected again - every level of a class hierarchy |
| 78 | + // repeats the interfaces it inherits, and the classes a node references share most of their |
| 79 | + // ancestors - is kept only once instead of being resolved to its file and package once more. |
77 | 80 | $dependenciesReflections = []; |
78 | 81 | $dependenciesFilePaths = []; |
79 | 82 |
|
@@ -181,7 +184,7 @@ public function resolveDependencies(Node $node, Scope $scope): NodeDependencies |
181 | 184 | if ($functionName instanceof Node\Name) { |
182 | 185 | try { |
183 | 186 | $functionReflection = $this->getFunctionReflection($functionName, $scope); |
184 | | - $dependenciesReflections[] = $functionReflection; |
| 187 | + $dependenciesReflections[spl_object_id($functionReflection)] = $functionReflection; |
185 | 188 |
|
186 | 189 | foreach ($functionReflection->getVariants() as $functionVariant) { |
187 | 190 | foreach ($functionVariant->getParameters() as $parameter) { |
@@ -408,7 +411,8 @@ public function resolveDependencies(Node $node, Scope $scope): NodeDependencies |
408 | 411 | !in_array($constantName->toLowerString(), ['true', 'false', 'null'], true) |
409 | 412 | && $this->reflectionProvider->hasConstant($constantName, $scope) |
410 | 413 | ) { |
411 | | - $dependenciesReflections[] = $this->reflectionProvider->getConstant($constantName, $scope); |
| 414 | + $constantReflection = $this->reflectionProvider->getConstant($constantName, $scope); |
| 415 | + $dependenciesReflections[spl_object_id($constantReflection)] = $constantReflection; |
412 | 416 | } |
413 | 417 | } elseif ($node instanceof Node\Expr\StaticPropertyFetch) { |
414 | 418 | if ($node->class instanceof Node\Name) { |
@@ -550,21 +554,13 @@ public function resolveDependencies(Node $node, Scope $scope): NodeDependencies |
550 | 554 | } |
551 | 555 | } |
552 | 556 | } elseif ($node instanceof StaticMethodCallableNode) { |
553 | | - foreach ($this->resolveDependencies(new Node\Expr\StaticCall($node->getClass(), $node->getName()), $scope)->getReflections() as $dependency) { |
554 | | - $dependenciesReflections[] = $dependency; |
555 | | - } |
| 557 | + $dependenciesReflections += $this->resolveDependencies(new Node\Expr\StaticCall($node->getClass(), $node->getName()), $scope)->getReflections(); |
556 | 558 | } elseif ($node instanceof MethodCallableNode) { |
557 | | - foreach ($this->resolveDependencies(new Node\Expr\MethodCall($node->getVar(), $node->getName()), $scope)->getReflections() as $dependency) { |
558 | | - $dependenciesReflections[] = $dependency; |
559 | | - } |
| 559 | + $dependenciesReflections += $this->resolveDependencies(new Node\Expr\MethodCall($node->getVar(), $node->getName()), $scope)->getReflections(); |
560 | 560 | } elseif ($node instanceof FunctionCallableNode) { |
561 | | - foreach ($this->resolveDependencies(new Node\Expr\FuncCall($node->getName()), $scope)->getReflections() as $dependency) { |
562 | | - $dependenciesReflections[] = $dependency; |
563 | | - } |
| 561 | + $dependenciesReflections += $this->resolveDependencies(new Node\Expr\FuncCall($node->getName()), $scope)->getReflections(); |
564 | 562 | } elseif ($node instanceof InstantiationCallableNode) { |
565 | | - foreach ($this->resolveDependencies(new Node\Expr\New_($node->getClass()), $scope)->getReflections() as $dependency) { |
566 | | - $dependenciesReflections[] = $dependency; |
567 | | - } |
| 563 | + $dependenciesReflections += $this->resolveDependencies(new Node\Expr\New_($node->getClass()), $scope)->getReflections(); |
568 | 564 | } |
569 | 565 |
|
570 | 566 | return new NodeDependencies($this->fileHelper, $dependenciesReflections, $this->exportedNodeResolver->resolve($node, $this->nameScopeTracker->getNameScope()), $dependenciesFilePaths); |
@@ -653,11 +649,11 @@ private function addClassToDependencies(string $className, array &$dependenciesR |
653 | 649 | $this->classDependencies[$className] = $this->buildClassDependencies($className); |
654 | 650 | } |
655 | 651 |
|
656 | | - $dependenciesReflections = array_merge($dependenciesReflections, $this->classDependencies[$className]); |
| 652 | + $dependenciesReflections += $this->classDependencies[$className]; |
657 | 653 | } |
658 | 654 |
|
659 | 655 | /** |
660 | | - * @return list<ClassReflection|FunctionReflection|ConstantReflection> |
| 656 | + * @return array<int, ClassReflection|FunctionReflection|ConstantReflection> |
661 | 657 | */ |
662 | 658 | private function buildClassDependencies(string $className): array |
663 | 659 | { |
@@ -809,7 +805,12 @@ private function buildClassDependencies(string $className): array |
809 | 805 | $classReflection = $classReflection->getParentClass(); |
810 | 806 | } while ($classReflection !== null); |
811 | 807 |
|
812 | | - return $dependencies; |
| 808 | + $uniqueDependencies = []; |
| 809 | + foreach ($dependencies as $dependency) { |
| 810 | + $uniqueDependencies[spl_object_id($dependency)] = $dependency; |
| 811 | + } |
| 812 | + |
| 813 | + return $uniqueDependencies; |
813 | 814 | } |
814 | 815 |
|
815 | 816 | private function getFunctionReflection(Node\Name $nameNode, ?Scope $scope): FunctionReflection |
|
0 commit comments