diff --git a/bench/property_fetch_finder_name_bench.php b/bench/property_fetch_finder_name_bench.php new file mode 100644 index 00000000000..90f213b1d4f --- /dev/null +++ b/bench/property_fetch_finder_name_bench.php @@ -0,0 +1,107 @@ +create(); +$rectorConfig->boot(); + +/** @var TestingParser $testingParser */ +$testingParser = $rectorConfig->make(TestingParser::class); + +/** @var BetterNodeFinder $betterNodeFinder */ +$betterNodeFinder = $rectorConfig->make(BetterNodeFinder::class); + +/** @var PropertyFetchFinder $propertyFetchFinder */ +$propertyFetchFinder = $rectorConfig->make(PropertyFetchFinder::class); + +// one target property, plus many methods that read unrelated properties $this->aK +$source = "a{$j}"; + } + $source .= implode(' + ', $parts) . ";\n }\n\n"; +} +$source .= " public function readTarget()\n {\n return \$this->target;\n }\n}\n"; + +$sourceFilePath = tempnam(sys_get_temp_dir(), 'bench_') . '.php'; +file_put_contents($sourceFilePath, $source); + +$stmts = $testingParser->parseFileToDecoratedNodes($sourceFilePath); + +/** @var Class_ $class */ +$class = $betterNodeFinder->findFirstInstanceOf($stmts, Class_::class); + +/** @var Property[] $properties */ +$properties = $betterNodeFinder->findInstanceOf($class, Property::class); +$targetProperty = $properties[0]; + +$scope = ScopeFetcher::fetch($class); + +$cpuSeconds = static function (): float { + $usage = getrusage(); + return $usage['ru_utime.tv_sec'] + $usage['ru_utime.tv_usec'] / 1_000_000 + + $usage['ru_stime.tv_sec'] + $usage['ru_stime.tv_usec'] / 1_000_000; +}; + +$run = static function () use ($propertyFetchFinder, $class, $targetProperty, $scope): void { + $propertyFetchFinder->findPrivatePropertyFetches($class, $targetProperty, $scope); +}; + +// warm up caches once, excluded from timing +$run(); + +$wallStart = microtime(true); +$cpuStart = $cpuSeconds(); + +for ($repeat = 0; $repeat < REPEAT; ++$repeat) { + $run(); +} + +$cpu = $cpuSeconds() - $cpuStart; +$wall = microtime(true) - $wallStart; + +@unlink($sourceFilePath); + +printf('property fetches scanned: %d, repeats: %d%s', METHODS * FETCHES_PER_METHOD + 1, REPEAT, PHP_EOL); +printf('CPU: %.4f s (%.3f ms/scan)%s', $cpu, $cpu / REPEAT * 1000, PHP_EOL); +printf('wall: %.4f s%s', $wall, PHP_EOL); diff --git a/src/PhpParser/NodeFinder/PropertyFetchFinder.php b/src/PhpParser/NodeFinder/PropertyFetchFinder.php index e971ed72020..a138dde4634 100644 --- a/src/PhpParser/NodeFinder/PropertyFetchFinder.php +++ b/src/PhpParser/NodeFinder/PropertyFetchFinder.php @@ -199,6 +199,11 @@ function (Node $subNode) use ($class, $hasTrait, $propertyName, $scope): bool { } if ($subNode instanceof PropertyFetch) { + // cheap name mismatch bail before the anonymous-class reflection lookup + if (! $this->nodeNameResolver->isName($subNode->name, $propertyName)) { + return false; + } + if ($this->isInAnonymous($subNode, $class, $hasTrait)) { return false; }