From 6ee14bf0a9353320f2a9b639c4ebcd128c3de3d6 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Fri, 29 Aug 2025 08:50:31 +0200 Subject: [PATCH 1/2] Faster MapBuilder->build() --- src/Target/MapBuilder.php | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/Target/MapBuilder.php b/src/Target/MapBuilder.php index 73395524f..eea151015 100644 --- a/src/Target/MapBuilder.php +++ b/src/Target/MapBuilder.php @@ -11,7 +11,6 @@ use function array_keys; use function array_merge; -use function array_merge_recursive; use function array_slice; use function array_unique; use function count; @@ -160,16 +159,28 @@ public function build(Filter $filter, FileAnalyser $analyser): array } foreach ($this->parentClasses($classDetails, $class) as $parentClass) { - $merged = array_merge_recursive( - $classes[$class->namespacedName()], - $classes[$parentClass->namespacedName()], - ); + // in big inheritance trees we might handle a lot of data. + // this inner loop needs to prevent unnecessary work whenever possible + foreach ($classes[$parentClass->namespacedName()] as $file => $lines) { + if (!isset($classes[$class->namespacedName()][$file])) { + $classes[$class->namespacedName()][$file] = $lines; - foreach ($merged as $mergedFile => $lines) { - $merged[$mergedFile] = array_unique($lines); - } + continue; + } + + if ( + $classes[$class->namespacedName()][$file] === $lines + ) { + continue; + } - $classes[$class->namespacedName()] = $merged; + $classes[$class->namespacedName()][$file] = array_unique( + array_merge( + $classes[$class->namespacedName()][$file], + $lines, + ), + ); + } if (isset($classesThatExtendClass[$parentClass->namespacedName()])) { $this->process($classesThatExtendClass, $parentClass->namespacedName(), $class->file(), $class->startLine(), $class->endLine()); From 6e58db649180114dce60d1206379e846e2e1213b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Fri, 29 Aug 2025 09:24:03 +0200 Subject: [PATCH 2/2] Refactor de-duplicate logic and re-use fast path in more places --- src/Target/MapBuilder.php | 80 +++++++++++++++------------------------ 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/src/Target/MapBuilder.php b/src/Target/MapBuilder.php index eea151015..ab4ed03c8 100644 --- a/src/Target/MapBuilder.php +++ b/src/Target/MapBuilder.php @@ -71,20 +71,7 @@ public function build(Filter $filter, FileAnalyser $analyser): array continue; } - $file = array_keys($traits[$traitName])[0]; - - if (!isset($traits[$trait->namespacedName()][$file])) { - $traits[$trait->namespacedName()][$file] = $traits[$traitName][$file]; - - continue; - } - - $traits[$trait->namespacedName()][$file] = array_unique( - array_merge( - $traits[$trait->namespacedName()][$file], - $traits[$traitName][$file], - ), - ); + $this->mergeLines($trait->namespacedName(), $traits[$traitName], $traits); } } } @@ -108,20 +95,7 @@ public function build(Filter $filter, FileAnalyser $analyser): array continue; } - foreach ($traits[$traitName] as $traitFile => $lines) { - if (!isset($classes[$class->namespacedName()][$traitFile])) { - $classes[$class->namespacedName()][$traitFile] = $lines; - - continue; - } - - $classes[$class->namespacedName()][$traitFile] = array_unique( - array_merge( - $classes[$class->namespacedName()][$traitFile], - $lines, - ), - ); - } + $this->mergeLines($class->namespacedName(), $traits[$traitName], $classes); } $this->processMethods($class, $file, $methods, $reverseLookup); @@ -159,28 +133,7 @@ public function build(Filter $filter, FileAnalyser $analyser): array } foreach ($this->parentClasses($classDetails, $class) as $parentClass) { - // in big inheritance trees we might handle a lot of data. - // this inner loop needs to prevent unnecessary work whenever possible - foreach ($classes[$parentClass->namespacedName()] as $file => $lines) { - if (!isset($classes[$class->namespacedName()][$file])) { - $classes[$class->namespacedName()][$file] = $lines; - - continue; - } - - if ( - $classes[$class->namespacedName()][$file] === $lines - ) { - continue; - } - - $classes[$class->namespacedName()][$file] = array_unique( - array_merge( - $classes[$class->namespacedName()][$file], - $lines, - ), - ); - } + $this->mergeLines($class->namespacedName(), $classes[$parentClass->namespacedName()], $classes); if (isset($classesThatExtendClass[$parentClass->namespacedName()])) { $this->process($classesThatExtendClass, $parentClass->namespacedName(), $class->file(), $class->startLine(), $class->endLine()); @@ -216,6 +169,33 @@ public function build(Filter $filter, FileAnalyser $analyser): array ]; } + private function mergeLines(string $targetClass, array $sourceData, array &$data): void + { + // in big inheritance trees we might handle a lot of data. + // this loop needs to prevent unnecessary work whenever possible. + + foreach ($sourceData as $file => $lines) { + if (!isset($data[$targetClass][$file])) { + $data[$targetClass][$file] = $lines; + + continue; + } + + if ( + $data[$targetClass][$file] === $lines + ) { + continue; + } + + $data[$targetClass][$file] = array_unique( + array_merge( + $data[$targetClass][$file], + $lines, + ), + ); + } + } + private function processMethods(Class_|Trait_ $classOrTrait, string $file, array &$methods, array &$reverseLookup): void { foreach ($classOrTrait->methods() as $method) {