From 965de74a8a05afd088b187a04c5ebb89128bf021 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Fri, 13 Feb 2026 16:34:16 +0100 Subject: [PATCH 01/13] DependencyResolver: Reduce duplicate work --- src/Dependency/DependencyResolver.php | 28 ++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 9ca07af7a9..9458f0f208 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -36,6 +36,10 @@ #[AutowiredService] final class DependencyResolver { + /** + * @var array + */ + private array $seenClasses = []; public function __construct( private FileHelper $fileHelper, @@ -521,6 +525,11 @@ private function considerArrayForCallableTest(Scope $scope, Array_ $arrayNode): */ private function addClassToDependencies(string $className, array &$dependenciesReflections): void { + if (isset($this->seenClasses[$className])) { + return; + } + $this->seenClasses[$className] = true; + try { $classReflection = $this->reflectionProvider->getClass($className); } catch (ClassNotFoundException) { @@ -676,12 +685,10 @@ private function extractFromParametersAcceptor( ): void { foreach ($parametersAcceptor->getParameters() as $parameter) { - $referencedClasses = array_merge( - $parameter->getNativeType()->getReferencedClasses(), - $parameter->getPhpDocType()->getReferencedClasses(), - ); - - foreach ($referencedClasses as $referencedClass) { + foreach ($parameter->getNativeType()->getReferencedClasses() as $referencedClass) { + $this->addClassToDependencies($referencedClass, $dependenciesReflections); + } + foreach ($parameter->getPhpDocType()->getReferencedClasses() as $referencedClass) { $this->addClassToDependencies($referencedClass, $dependenciesReflections); } @@ -698,11 +705,10 @@ private function extractFromParametersAcceptor( } } - $returnTypeReferencedClasses = array_merge( - $parametersAcceptor->getNativeReturnType()->getReferencedClasses(), - $parametersAcceptor->getPhpDocReturnType()->getReferencedClasses(), - ); - foreach ($returnTypeReferencedClasses as $referencedClass) { + foreach ($parametersAcceptor->getNativeReturnType()->getReferencedClasses() as $referencedClass) { + $this->addClassToDependencies($referencedClass, $dependenciesReflections); + } + foreach ($parametersAcceptor->getPhpDocReturnType()->getReferencedClasses() as $referencedClass) { $this->addClassToDependencies($referencedClass, $dependenciesReflections); } } From 2e17cae497cd9949d94534d91ab26a85d2f627d1 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Fri, 13 Feb 2026 16:41:47 +0100 Subject: [PATCH 02/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 9458f0f208..632cd2b3dd 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -30,15 +30,13 @@ use PHPStan\Type\ClosureType; use PHPStan\Type\FileTypeMapper; use PHPStan\Type\Type; -use function array_merge; use function count; #[AutowiredService] final class DependencyResolver { - /** - * @var array - */ + + /** @var array */ private array $seenClasses = []; public function __construct( From 98b53e20e94a9e125ed03012dd1ed48d61e2c05a Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Fri, 13 Feb 2026 16:54:14 +0100 Subject: [PATCH 03/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 632cd2b3dd..4baeadc1d0 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -526,10 +526,10 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (isset($this->seenClasses[$className])) { return; } - $this->seenClasses[$className] = true; try { $classReflection = $this->reflectionProvider->getClass($className); + $this->seenClasses[$className] = true; } catch (ClassNotFoundException) { return; } From b0a6ed00a3ce6921be481d04e48be51b2244f37d Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Fri, 13 Feb 2026 17:06:03 +0100 Subject: [PATCH 04/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 4baeadc1d0..b6d08872ff 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -523,17 +523,20 @@ private function considerArrayForCallableTest(Scope $scope, Array_ $arrayNode): */ private function addClassToDependencies(string $className, array &$dependenciesReflections): void { - if (isset($this->seenClasses[$className])) { - return; - } - try { $classReflection = $this->reflectionProvider->getClass($className); - $this->seenClasses[$className] = true; } catch (ClassNotFoundException) { return; } + $fileName = $classReflection->getFileName(); + if ($fileName !== null) { + if (isset($this->seenClasses[$fileName])) { + return; + } + $this->seenClasses[$fileName] = true; + } + do { $dependenciesReflections[] = $classReflection; From 5db6189e4d9bd609ec40e5969959cf92b589f038 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Fri, 13 Feb 2026 17:13:42 +0100 Subject: [PATCH 05/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index b6d08872ff..c10b86c97b 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -531,10 +531,11 @@ private function addClassToDependencies(string $className, array &$dependenciesR $fileName = $classReflection->getFileName(); if ($fileName !== null) { - if (isset($this->seenClasses[$fileName])) { + $classKey = $className . '-' . $fileName; + if (isset($this->seenClasses[$classKey])) { return; } - $this->seenClasses[$fileName] = true; + $this->seenClasses[$classKey] = true; } do { From 994319cc17377478a5c004019cf03d6831cae3bd Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Fri, 13 Feb 2026 17:21:21 +0100 Subject: [PATCH 06/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index c10b86c97b..648f6dbfe4 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -529,14 +529,11 @@ private function addClassToDependencies(string $className, array &$dependenciesR return; } - $fileName = $classReflection->getFileName(); - if ($fileName !== null) { - $classKey = $className . '-' . $fileName; - if (isset($this->seenClasses[$classKey])) { - return; - } - $this->seenClasses[$classKey] = true; + $cacheKey = $classReflection->getCacheKey(); + if (isset($this->seenClasses[$cacheKey])) { + return; } + $this->seenClasses[$cacheKey] = true; do { $dependenciesReflections[] = $classReflection; From f5615516e73f6d6577bd25a6a09fd0e6e1a2c8ec Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 14 Feb 2026 06:42:38 +0100 Subject: [PATCH 07/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 648f6dbfe4..8b32ccfb24 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -529,11 +529,13 @@ private function addClassToDependencies(string $className, array &$dependenciesR return; } - $cacheKey = $classReflection->getCacheKey(); - if (isset($this->seenClasses[$cacheKey])) { - return; + if (!$classReflection->isGeneric()) { + $cacheKey = $classReflection->getCacheKey(); + if (isset($this->seenClasses[$cacheKey])) { + return; + } + $this->seenClasses[$cacheKey] = true; } - $this->seenClasses[$cacheKey] = true; do { $dependenciesReflections[] = $classReflection; From 2abf3f52e1f98fd61a7b2497f20b22694fc16d60 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 14 Feb 2026 06:53:18 +0100 Subject: [PATCH 08/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 8b32ccfb24..602d8a41ce 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -529,8 +529,8 @@ private function addClassToDependencies(string $className, array &$dependenciesR return; } - if (!$classReflection->isGeneric()) { - $cacheKey = $classReflection->getCacheKey(); + if ($classReflection->getTemplateTypeMap()->isEmpty()) { + $cacheKey = $className .'-'. $classReflection->getFileName(); if (isset($this->seenClasses[$cacheKey])) { return; } From 5bf9d03c4831eb4973d7b1f315519badf3fab7ee Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 14 Feb 2026 07:04:56 +0100 Subject: [PATCH 09/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 602d8a41ce..0842ad1c2a 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -530,7 +530,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR } if ($classReflection->getTemplateTypeMap()->isEmpty()) { - $cacheKey = $className .'-'. $classReflection->getFileName(); + $cacheKey = $classReflection->getCacheKey(); if (isset($this->seenClasses[$cacheKey])) { return; } From e9387afbdef3cdbafbf780cedd7986a67d7b3c1b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 14 Feb 2026 07:10:00 +0100 Subject: [PATCH 10/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 0842ad1c2a..c4eeba5642 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -529,13 +529,11 @@ private function addClassToDependencies(string $className, array &$dependenciesR return; } - if ($classReflection->getTemplateTypeMap()->isEmpty()) { - $cacheKey = $classReflection->getCacheKey(); - if (isset($this->seenClasses[$cacheKey])) { - return; - } - $this->seenClasses[$cacheKey] = true; + $cacheKey = spl_object_id($classReflection); + if (isset($this->seenClasses[$cacheKey])) { + return; } + $this->seenClasses[$cacheKey] = true; do { $dependenciesReflections[] = $classReflection; From 567763bce6c12c635e23631482f1e906bffcd6ec Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 14 Feb 2026 11:09:42 +0100 Subject: [PATCH 11/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 59 +++++++++++++++------------ 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index c4eeba5642..f5da09b292 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -36,8 +36,8 @@ final class DependencyResolver { - /** @var array */ - private array $seenClasses = []; + /** @var array */ + private array $classDependencies = []; public function __construct( private FileHelper $fileHelper, @@ -522,28 +522,35 @@ private function considerArrayForCallableTest(Scope $scope, Array_ $arrayNode): * @param array $dependenciesReflections */ private function addClassToDependencies(string $className, array &$dependenciesReflections): void + { + if (!array_key_exists($className, $this->classDependencies)) { + $this->classDependencies[$className] = $this->buildClassToDependencies($className); + } + + $dependenciesReflections = array_merge($dependenciesReflections, $this->classDependencies[$className]); + } + + /** + * @return list + */ + private function buildClassToDependencies(string $className): array { try { $classReflection = $this->reflectionProvider->getClass($className); } catch (ClassNotFoundException) { - return; - } - - $cacheKey = spl_object_id($classReflection); - if (isset($this->seenClasses[$cacheKey])) { - return; + return []; } - $this->seenClasses[$cacheKey] = true; + $dependencies = []; do { - $dependenciesReflections[] = $classReflection; + $dependencies[] = $classReflection; foreach ($classReflection->getInterfaces() as $interface) { - $dependenciesReflections[] = $interface; + $dependencies[] = $interface; } foreach ($classReflection->getTraits(true) as $trait) { - $dependenciesReflections[] = $trait; + $dependencies[] = $trait; } foreach ($classReflection->getResolvedMixinTypes() as $mixinType) { @@ -551,7 +558,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } } @@ -560,7 +567,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } } @@ -569,7 +576,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } } @@ -578,7 +585,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } $default = $templateTag->getDefault(); @@ -589,7 +596,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } } @@ -599,7 +606,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } } @@ -611,7 +618,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } } @@ -620,14 +627,14 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } foreach ($methodTag->getParameters() as $parameter) { foreach ($parameter->getType()->getReferencedClasses() as $referencedClass) { if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } if ($parameter->getDefaultValue() === null) { continue; @@ -636,7 +643,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } } } @@ -646,7 +653,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } } @@ -655,19 +662,21 @@ private function addClassToDependencies(string $className, array &$dependenciesR if (!$this->reflectionProvider->hasClass($referencedClass)) { continue; } - $dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass); + $dependencies[] = $this->reflectionProvider->getClass($referencedClass); } } $phpDoc = $classReflection->getResolvedPhpDoc(); if ($phpDoc !== null) { foreach ($phpDoc->getTypeAliasImportTags() as $importTag) { - $dependenciesReflections[] = $this->reflectionProvider->getClass($importTag->getImportedFrom()); + $dependencies[] = $this->reflectionProvider->getClass($importTag->getImportedFrom()); } } $classReflection = $classReflection->getParentClass(); } while ($classReflection !== null); + + return $dependencies; } private function getFunctionReflection(Node\Name $nameNode, ?Scope $scope): FunctionReflection From 1bb86bb0774efbf25b9ef3f30964ae83de5b4a8d Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 14 Feb 2026 11:21:42 +0100 Subject: [PATCH 12/13] Update DependencyResolver.php --- src/Dependency/DependencyResolver.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index f5da09b292..f799a8cedd 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -36,7 +36,7 @@ final class DependencyResolver { - /** @var array */ + /** @var array> */ private array $classDependencies = []; public function __construct( @@ -524,16 +524,16 @@ private function considerArrayForCallableTest(Scope $scope, Array_ $arrayNode): private function addClassToDependencies(string $className, array &$dependenciesReflections): void { if (!array_key_exists($className, $this->classDependencies)) { - $this->classDependencies[$className] = $this->buildClassToDependencies($className); + $this->classDependencies[$className] = $this->buildClassDependencies($className); } $dependenciesReflections = array_merge($dependenciesReflections, $this->classDependencies[$className]); } /** - * @return list + * @return list */ - private function buildClassToDependencies(string $className): array + private function buildClassDependencies(string $className): array { try { $classReflection = $this->reflectionProvider->getClass($className); From 881eba0c4d3c7eaad12818d2ec774478975d9af9 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 14 Feb 2026 11:34:44 +0100 Subject: [PATCH 13/13] cs --- src/Dependency/DependencyResolver.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index f799a8cedd..87677b0f7f 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -30,6 +30,8 @@ use PHPStan\Type\ClosureType; use PHPStan\Type\FileTypeMapper; use PHPStan\Type\Type; +use function array_key_exists; +use function array_merge; use function count; #[AutowiredService]