From eac798582cf1f0110144248d85cfe595f94c8239 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 11 Jul 2026 17:40:24 +0200 Subject: [PATCH 1/3] Faster DuplicateClassDeclarationRule --- .../Classes/DuplicateClassDeclarationRule.php | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Rules/Classes/DuplicateClassDeclarationRule.php b/src/Rules/Classes/DuplicateClassDeclarationRule.php index 72632aedc24..543f745d16c 100644 --- a/src/Rules/Classes/DuplicateClassDeclarationRule.php +++ b/src/Rules/Classes/DuplicateClassDeclarationRule.php @@ -24,6 +24,7 @@ #[ValidatesStubFiles] final class DuplicateClassDeclarationRule implements Rule { + private ?array $classMap = null; public function __construct(private Reflector $reflector, private RelativePathHelper $relativePathHelper) { @@ -38,21 +39,25 @@ public function processNode(Node $node, Scope $scope): array { $thisClass = $node->getClassReflection(); $className = $thisClass->getName(); - $allClasses = $this->reflector->reflectAllClasses(); - $filteredClasses = []; - foreach ($allClasses as $reflectionClass) { - if ($reflectionClass->getName() !== $className) { - continue; - } - $filteredClasses[] = $reflectionClass; + if ($this->classMap === null) { + $this->classMap = []; + + $allClasses = $this->reflector->reflectAllClasses(); + foreach ($allClasses as $reflectionClass) { + $reflectionClassName = $reflectionClass->getName(); + if (!isset($this->classMap[$reflectionClassName])) { + $this->classMap[$reflectionClassName] = []; + } + $this->classMap[$reflectionClassName][] = $reflectionClass; + } } - if (count($filteredClasses) < 2) { + if (!isset($this->classMap[$className]) || count($this->classMap[$className]) < 2) { return []; } - $filteredClasses = array_filter($filteredClasses, static fn (ReflectionClass $class) => $class->getStartLine() !== $thisClass->getNativeReflection()->getStartLine()); + $filteredClasses = array_filter($this->classMap[$className], static fn (ReflectionClass $class) => $class->getStartLine() !== $thisClass->getNativeReflection()->getStartLine()); $identifierType = strtolower($thisClass->getClassTypeDescription()); From 3c870426e413e8e76822db6ac1acad3f9a2557ab Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 11 Jul 2026 17:47:03 +0200 Subject: [PATCH 2/3] fix build --- src/Rules/Classes/DuplicateClassDeclarationRule.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Rules/Classes/DuplicateClassDeclarationRule.php b/src/Rules/Classes/DuplicateClassDeclarationRule.php index 543f745d16c..282834b72b4 100644 --- a/src/Rules/Classes/DuplicateClassDeclarationRule.php +++ b/src/Rules/Classes/DuplicateClassDeclarationRule.php @@ -9,6 +9,7 @@ use PHPStan\DependencyInjection\ValidatesStubFiles; use PHPStan\File\RelativePathHelper; use PHPStan\Node\InClassNode; +use PHPStan\Reflection\ClassReflection; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use function array_filter; @@ -24,6 +25,8 @@ #[ValidatesStubFiles] final class DuplicateClassDeclarationRule implements Rule { + + /** @var array>|null */ private ?array $classMap = null; public function __construct(private Reflector $reflector, private RelativePathHelper $relativePathHelper) @@ -40,6 +43,8 @@ public function processNode(Node $node, Scope $scope): array $thisClass = $node->getClassReflection(); $className = $thisClass->getName(); + // this rule runs at the very end of the analysis, + // so all classes already have been discovered at this point. if ($this->classMap === null) { $this->classMap = []; From 827a51a26c30d0a7ab965deaa4bab75793cd9a61 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 11 Jul 2026 17:51:13 +0200 Subject: [PATCH 3/3] cs --- src/Rules/Classes/DuplicateClassDeclarationRule.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Rules/Classes/DuplicateClassDeclarationRule.php b/src/Rules/Classes/DuplicateClassDeclarationRule.php index 282834b72b4..a07a63c00a9 100644 --- a/src/Rules/Classes/DuplicateClassDeclarationRule.php +++ b/src/Rules/Classes/DuplicateClassDeclarationRule.php @@ -9,7 +9,6 @@ use PHPStan\DependencyInjection\ValidatesStubFiles; use PHPStan\File\RelativePathHelper; use PHPStan\Node\InClassNode; -use PHPStan\Reflection\ClassReflection; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use function array_filter;