Skip to content

Commit 6a888e8

Browse files
committed
feature symfony#54894 [PropertyInfo] Adds static cache to PhpStanExtractor (mvhirsch)
This PR was squashed before being merged into the 7.2 branch. Discussion ---------- [PropertyInfo] Adds static cache to `PhpStanExtractor` | Q | A | ------------- | --- | Branch? | 7.2 | Bug fix? | no (performance) | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Issues | <!-- prefix each issue number with "Fix #", no need to create an issue if none exists, explain below instead --> | License | MIT I was able to detect a performance penalty when using dozens of traits in even more classes. The `PhpStanExtractor ` creates a `NameScope` every time, but afaik this can be cached like in `PhpDocExtractor` (see symfony#32188). The performance impact is impressive, as it reduces the time needed for my `TestCase` by 30%. See [Blackfire profile comparison](https://blackfire.io/profiles/compare/9eb78784-fa68-4721-9c87-f2be52da2d63/graph). <!-- Replace this notice by a description of your feature/bugfix. This will help reviewers and should be a good start for the documentation. Additionally (see https://symfony.com/releases): - Always add tests and ensure they pass. - Bug fixes must be submitted against the lowest maintained branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the latest branch. - For new features, provide some code snippets to help understand usage. - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry - Never break backward compatibility (see https://symfony.com/bc). --> Commits ------- 9697351 [PropertyInfo] Adds static cache to `PhpStanExtractor`
2 parents fbcdba1 + 9697351 commit 6a888e8

File tree

2 files changed

+10
-2
lines changed

2 files changed

+10
-2
lines changed

src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use PHPStan\PhpDocParser\Parser\PhpDocParser;
2222
use PHPStan\PhpDocParser\Parser\TokenIterator;
2323
use PHPStan\PhpDocParser\Parser\TypeParser;
24+
use Symfony\Component\PropertyInfo\PhpStan\NameScope;
2425
use Symfony\Component\PropertyInfo\PhpStan\NameScopeFactory;
2526
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
2627
use Symfony\Component\PropertyInfo\Type as LegacyType;
@@ -55,6 +56,9 @@ final class PhpStanExtractor implements PropertyTypeExtractorInterface, Construc
5556
private array $accessorPrefixes;
5657
private array $arrayMutatorPrefixes;
5758

59+
/** @var array<string, NameScope> */
60+
private array $contexts = [];
61+
5862
/**
5963
* @param list<string>|null $mutatorPrefixes
6064
* @param list<string>|null $accessorPrefixes
@@ -86,7 +90,6 @@ public function getTypes(string $class, string $property, array $context = []):
8690
{
8791
/** @var PhpDocNode|null $docNode */
8892
[$docNode, $source, $prefix, $declaringClass] = $this->getDocBlock($class, $property);
89-
$nameScope = $this->nameScopeFactory->create($class, $declaringClass);
9093
if (null === $docNode) {
9194
return null;
9295
}
@@ -120,6 +123,7 @@ public function getTypes(string $class, string $property, array $context = []):
120123
continue;
121124
}
122125

126+
$nameScope ??= $this->contexts[$class.'/'.$declaringClass] ??= $this->nameScopeFactory->create($class, $declaringClass);
123127
foreach ($this->phpStanTypeHelper->getTypes($tagDocNode->value, $nameScope) as $type) {
124128
switch ($type->getClassName()) {
125129
case 'self':

src/Symfony/Component/PropertyInfo/PhpStan/NameScopeFactory.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\PropertyInfo\PhpStan;
1313

14+
use phpDocumentor\Reflection\Types\Context;
1415
use phpDocumentor\Reflection\Types\ContextFactory;
1516

1617
/**
@@ -20,6 +21,9 @@
2021
*/
2122
final class NameScopeFactory
2223
{
24+
/** @var array<string, Context> */
25+
private array $contexts = [];
26+
2327
public function create(string $calledClassName, ?string $declaringClassName = null): NameScope
2428
{
2529
$declaringClassName ??= $calledClassName;
@@ -60,7 +64,7 @@ private function extractFromFullClassName(\ReflectionClass $reflection): array
6064
}
6165

6266
$factory = new ContextFactory();
63-
$context = $factory->createForNamespace($namespace, $contents);
67+
$context = $this->contexts[$namespace.$fileName] ??= $factory->createForNamespace($namespace, $contents);
6468

6569
return [$namespace, $context->getNamespaceAliases()];
6670
}

0 commit comments

Comments
 (0)