Skip to content

Commit 7adebeb

Browse files
committed
ScopeFactory - lower the chance of a circular dependency
1 parent 7feecd3 commit 7adebeb

File tree

6 files changed

+215
-83
lines changed

6 files changed

+215
-83
lines changed

conf/config.neon

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,9 +263,11 @@ services:
263263
class: PHPStan\Analyser\FileAnalyser
264264

265265
-
266-
class: PHPStan\Analyser\ScopeFactory
266+
class: PHPStan\Analyser\LazyScopeFactory
267267
arguments:
268268
scopeClass: %scopeClass%
269+
autowired:
270+
- PHPStan\Analyser\ScopeFactory
269271

270272
-
271273
class: PHPStan\Analyser\NodeScopeResolver
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser;
4+
5+
use PHPStan\DependencyInjection\Container;
6+
use PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider;
7+
use PHPStan\DependencyInjection\Type\OperatorTypeSpecifyingExtensionRegistryProvider;
8+
use PHPStan\Reflection\ParametersAcceptor;
9+
use PHPStan\Reflection\ReflectionProvider;
10+
use PHPStan\Rules\Properties\PropertyReflectionFinder;
11+
12+
/**
13+
* @internal
14+
*/
15+
class DirectScopeFactory implements ScopeFactory
16+
{
17+
18+
/** @var string */
19+
private $scopeClass;
20+
21+
/** @var \PHPStan\Reflection\ReflectionProvider */
22+
private $reflectionProvider;
23+
24+
/** @var \PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider */
25+
private $dynamicReturnTypeExtensionRegistryProvider;
26+
27+
/** @var OperatorTypeSpecifyingExtensionRegistryProvider */
28+
private $operatorTypeSpecifyingExtensionRegistryProvider;
29+
30+
/** @var \PhpParser\PrettyPrinter\Standard */
31+
private $printer;
32+
33+
/** @var \PHPStan\Analyser\TypeSpecifier */
34+
private $typeSpecifier;
35+
36+
/** @var \PHPStan\Rules\Properties\PropertyReflectionFinder */
37+
private $propertyReflectionFinder;
38+
39+
/** @var string[] */
40+
private $dynamicConstantNames;
41+
42+
public function __construct(
43+
string $scopeClass,
44+
ReflectionProvider $reflectionProvider,
45+
DynamicReturnTypeExtensionRegistryProvider $dynamicReturnTypeExtensionRegistryProvider,
46+
OperatorTypeSpecifyingExtensionRegistryProvider $operatorTypeSpecifyingExtensionRegistryProvider,
47+
\PhpParser\PrettyPrinter\Standard $printer,
48+
TypeSpecifier $typeSpecifier,
49+
PropertyReflectionFinder $propertyReflectionFinder,
50+
Container $container
51+
)
52+
{
53+
$this->scopeClass = $scopeClass;
54+
$this->reflectionProvider = $reflectionProvider;
55+
$this->dynamicReturnTypeExtensionRegistryProvider = $dynamicReturnTypeExtensionRegistryProvider;
56+
$this->operatorTypeSpecifyingExtensionRegistryProvider = $operatorTypeSpecifyingExtensionRegistryProvider;
57+
$this->printer = $printer;
58+
$this->typeSpecifier = $typeSpecifier;
59+
$this->propertyReflectionFinder = $propertyReflectionFinder;
60+
$this->dynamicConstantNames = $container->getParameter('dynamicConstantNames');
61+
}
62+
63+
/**
64+
* @param \PHPStan\Analyser\ScopeContext $context
65+
* @param bool $declareStrictTypes
66+
* @param \PHPStan\Reflection\FunctionReflection|\PHPStan\Reflection\MethodReflection|null $function
67+
* @param string|null $namespace
68+
* @param \PHPStan\Analyser\VariableTypeHolder[] $variablesTypes
69+
* @param \PHPStan\Analyser\VariableTypeHolder[] $moreSpecificTypes
70+
* @param string|null $inClosureBindScopeClass
71+
* @param \PHPStan\Reflection\ParametersAcceptor|null $anonymousFunctionReflection
72+
* @param bool $inFirstLevelStatement
73+
* @param array<string, true> $currentlyAssignedExpressions
74+
*
75+
* @return MutatingScope
76+
*/
77+
public function create(
78+
ScopeContext $context,
79+
bool $declareStrictTypes = false,
80+
$function = null,
81+
?string $namespace = null,
82+
array $variablesTypes = [],
83+
array $moreSpecificTypes = [],
84+
?string $inClosureBindScopeClass = null,
85+
?ParametersAcceptor $anonymousFunctionReflection = null,
86+
bool $inFirstLevelStatement = true,
87+
array $currentlyAssignedExpressions = []
88+
): MutatingScope
89+
{
90+
$scopeClass = $this->scopeClass;
91+
if (!is_a($scopeClass, MutatingScope::class, true)) {
92+
throw new \PHPStan\ShouldNotHappenException();
93+
}
94+
95+
return new $scopeClass(
96+
$this,
97+
$this->reflectionProvider,
98+
$this->dynamicReturnTypeExtensionRegistryProvider->getRegistry(),
99+
$this->operatorTypeSpecifyingExtensionRegistryProvider->getRegistry(),
100+
$this->printer,
101+
$this->typeSpecifier,
102+
$this->propertyReflectionFinder,
103+
$context,
104+
$declareStrictTypes,
105+
$function,
106+
$namespace,
107+
$variablesTypes,
108+
$moreSpecificTypes,
109+
$inClosureBindScopeClass,
110+
$anonymousFunctionReflection,
111+
$inFirstLevelStatement,
112+
$currentlyAssignedExpressions,
113+
$this->dynamicConstantNames
114+
);
115+
}
116+
117+
}

src/Analyser/LazyScopeFactory.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser;
4+
5+
use PhpParser\PrettyPrinter\Standard;
6+
use PHPStan\DependencyInjection\Container;
7+
use PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider;
8+
use PHPStan\DependencyInjection\Type\OperatorTypeSpecifyingExtensionRegistryProvider;
9+
use PHPStan\Reflection\ParametersAcceptor;
10+
use PHPStan\Reflection\ReflectionProvider;
11+
use PHPStan\Rules\Properties\PropertyReflectionFinder;
12+
13+
class LazyScopeFactory implements ScopeFactory
14+
{
15+
16+
/** @var string */
17+
private $scopeClass;
18+
19+
/** @var Container */
20+
private $container;
21+
22+
/** @var string[] */
23+
private $dynamicConstantNames;
24+
25+
public function __construct(
26+
string $scopeClass,
27+
Container $container
28+
)
29+
{
30+
$this->scopeClass = $scopeClass;
31+
$this->container = $container;
32+
$this->dynamicConstantNames = $container->getParameter('dynamicConstantNames');
33+
}
34+
35+
/**
36+
* @param \PHPStan\Analyser\ScopeContext $context
37+
* @param bool $declareStrictTypes
38+
* @param \PHPStan\Reflection\FunctionReflection|\PHPStan\Reflection\MethodReflection|null $function
39+
* @param string|null $namespace
40+
* @param \PHPStan\Analyser\VariableTypeHolder[] $variablesTypes
41+
* @param \PHPStan\Analyser\VariableTypeHolder[] $moreSpecificTypes
42+
* @param string|null $inClosureBindScopeClass
43+
* @param \PHPStan\Reflection\ParametersAcceptor|null $anonymousFunctionReflection
44+
* @param bool $inFirstLevelStatement
45+
* @param array<string, true> $currentlyAssignedExpressions
46+
*
47+
* @return MutatingScope
48+
*/
49+
public function create(
50+
ScopeContext $context,
51+
bool $declareStrictTypes = false,
52+
$function = null,
53+
?string $namespace = null,
54+
array $variablesTypes = [],
55+
array $moreSpecificTypes = [],
56+
?string $inClosureBindScopeClass = null,
57+
?ParametersAcceptor $anonymousFunctionReflection = null,
58+
bool $inFirstLevelStatement = true,
59+
array $currentlyAssignedExpressions = []
60+
): MutatingScope
61+
{
62+
$scopeClass = $this->scopeClass;
63+
if (!is_a($scopeClass, MutatingScope::class, true)) {
64+
throw new \PHPStan\ShouldNotHappenException();
65+
}
66+
67+
return new $scopeClass(
68+
$this,
69+
$this->container->getByType(ReflectionProvider::class),
70+
$this->container->getByType(DynamicReturnTypeExtensionRegistryProvider::class)->getRegistry(),
71+
$this->container->getByType(OperatorTypeSpecifyingExtensionRegistryProvider::class)->getRegistry(),
72+
$this->container->getByType(Standard::class),
73+
$this->container->getByType(TypeSpecifier::class),
74+
$this->container->getByType(PropertyReflectionFinder::class),
75+
$context,
76+
$declareStrictTypes,
77+
$function,
78+
$namespace,
79+
$variablesTypes,
80+
$moreSpecificTypes,
81+
$inClosureBindScopeClass,
82+
$anonymousFunctionReflection,
83+
$inFirstLevelStatement,
84+
$currentlyAssignedExpressions,
85+
$this->dynamicConstantNames
86+
);
87+
}
88+
89+
}

src/Analyser/ScopeFactory.php

Lines changed: 2 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,11 @@
22

33
namespace PHPStan\Analyser;
44

5-
use PHPStan\DependencyInjection\Container;
6-
use PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider;
7-
use PHPStan\DependencyInjection\Type\OperatorTypeSpecifyingExtensionRegistryProvider;
85
use PHPStan\Reflection\ParametersAcceptor;
9-
use PHPStan\Reflection\ReflectionProvider;
10-
use PHPStan\Rules\Properties\PropertyReflectionFinder;
116

12-
class ScopeFactory
7+
interface ScopeFactory
138
{
149

15-
/** @var string */
16-
private $scopeClass;
17-
18-
/** @var \PHPStan\Reflection\ReflectionProvider */
19-
private $reflectionProvider;
20-
21-
/** @var \PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider */
22-
private $dynamicReturnTypeExtensionRegistryProvider;
23-
24-
/** @var OperatorTypeSpecifyingExtensionRegistryProvider */
25-
private $operatorTypeSpecifyingExtensionRegistryProvider;
26-
27-
/** @var \PhpParser\PrettyPrinter\Standard */
28-
private $printer;
29-
30-
/** @var \PHPStan\Analyser\TypeSpecifier */
31-
private $typeSpecifier;
32-
33-
/** @var \PHPStan\Rules\Properties\PropertyReflectionFinder */
34-
private $propertyReflectionFinder;
35-
36-
/** @var string[] */
37-
private $dynamicConstantNames;
38-
39-
public function __construct(
40-
string $scopeClass,
41-
ReflectionProvider $reflectionProvider,
42-
DynamicReturnTypeExtensionRegistryProvider $dynamicReturnTypeExtensionRegistryProvider,
43-
OperatorTypeSpecifyingExtensionRegistryProvider $operatorTypeSpecifyingExtensionRegistryProvider,
44-
\PhpParser\PrettyPrinter\Standard $printer,
45-
TypeSpecifier $typeSpecifier,
46-
PropertyReflectionFinder $propertyReflectionFinder,
47-
Container $container
48-
)
49-
{
50-
$this->scopeClass = $scopeClass;
51-
$this->reflectionProvider = $reflectionProvider;
52-
$this->dynamicReturnTypeExtensionRegistryProvider = $dynamicReturnTypeExtensionRegistryProvider;
53-
$this->operatorTypeSpecifyingExtensionRegistryProvider = $operatorTypeSpecifyingExtensionRegistryProvider;
54-
$this->printer = $printer;
55-
$this->typeSpecifier = $typeSpecifier;
56-
$this->propertyReflectionFinder = $propertyReflectionFinder;
57-
$this->dynamicConstantNames = $container->getParameter('dynamicConstantNames');
58-
}
59-
6010
/**
6111
* @param \PHPStan\Analyser\ScopeContext $context
6212
* @param bool $declareStrictTypes
@@ -82,33 +32,6 @@ public function create(
8232
?ParametersAcceptor $anonymousFunctionReflection = null,
8333
bool $inFirstLevelStatement = true,
8434
array $currentlyAssignedExpressions = []
85-
): MutatingScope
86-
{
87-
$scopeClass = $this->scopeClass;
88-
if (!is_a($scopeClass, MutatingScope::class, true)) {
89-
throw new \PHPStan\ShouldNotHappenException();
90-
}
91-
92-
return new $scopeClass(
93-
$this,
94-
$this->reflectionProvider,
95-
$this->dynamicReturnTypeExtensionRegistryProvider->getRegistry(),
96-
$this->operatorTypeSpecifyingExtensionRegistryProvider->getRegistry(),
97-
$this->printer,
98-
$this->typeSpecifier,
99-
$this->propertyReflectionFinder,
100-
$context,
101-
$declareStrictTypes,
102-
$function,
103-
$namespace,
104-
$variablesTypes,
105-
$moreSpecificTypes,
106-
$inClosureBindScopeClass,
107-
$anonymousFunctionReflection,
108-
$inFirstLevelStatement,
109-
$currentlyAssignedExpressions,
110-
$this->dynamicConstantNames
111-
);
112-
}
35+
): MutatingScope;
11336

11437
}

src/Testing/TestCase.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Testing;
44

55
use PhpParser\PrettyPrinter\Standard;
6+
use PHPStan\Analyser\DirectScopeFactory;
67
use PHPStan\Analyser\MutatingScope;
78
use PHPStan\Analyser\NodeScopeResolver;
89
use PHPStan\Analyser\ScopeFactory;
@@ -450,15 +451,15 @@ public function createScopeFactory(Broker $broker, TypeSpecifier $typeSpecifier)
450451
{
451452
$container = self::getContainer();
452453

453-
return new ScopeFactory(
454+
return new DirectScopeFactory(
454455
MutatingScope::class,
455456
$broker,
456457
$broker->getDynamicReturnTypeExtensionRegistryProvider(),
457458
$broker->getOperatorTypeSpecifyingExtensionRegistryProvider(),
458459
new \PhpParser\PrettyPrinter\Standard(),
459460
$typeSpecifier,
460461
new PropertyReflectionFinder(),
461-
$container->getByType(Container::class)
462+
$container
462463
);
463464
}
464465

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10342,7 +10342,7 @@ private function processFile(
1034210342

1034310343
$scopeFactory = $this->createScopeFactory($broker, $typeSpecifier);
1034410344
if (count($dynamicConstantNames) > 0) {
10345-
$reflectionProperty = new \ReflectionProperty(ScopeFactory::class, 'dynamicConstantNames');
10345+
$reflectionProperty = new \ReflectionProperty(DirectScopeFactory::class, 'dynamicConstantNames');
1034610346
$reflectionProperty->setAccessible(true);
1034710347
$reflectionProperty->setValue($scopeFactory, $dynamicConstantNames);
1034810348
}

0 commit comments

Comments
 (0)