Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8793f30

Browse files
Add ability to check if a variable is global in scope
1 parent 9d81092 commit 8793f30

File tree

8 files changed

+93
-8
lines changed

8 files changed

+93
-8
lines changed

‎src/Analyser/DirectInternalScopeFactory.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public function create(
5656
bool $afterExtractCall = false,
5757
?Scope $parentScope = null,
5858
bool $nativeTypesPromoted = false,
59+
array $globalVariables = [],
5960
): MutatingScope
6061
{
6162
return new MutatingScope(
@@ -90,6 +91,7 @@ public function create(
9091
$afterExtractCall,
9192
$parentScope,
9293
$nativeTypesPromoted,
94+
$globalVariables,
9395
);
9496
}
9597

‎src/Analyser/InternalScopeFactory.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ interface InternalScopeFactory
1919
* @param array<string, true> $currentlyAssignedExpressions
2020
* @param array<string, true> $currentlyAllowedUndefinedExpressions
2121
* @param list<array{FunctionReflection|MethodReflection|null, ParameterReflection|null}> $inFunctionCallsStack
22+
* @param list<string> $globalVariables
2223
*/
2324
public function create(
2425
ScopeContext $context,
@@ -37,6 +38,7 @@ public function create(
3738
bool $afterExtractCall = false,
3839
?Scope $parentScope = null,
3940
bool $nativeTypesPromoted = false,
41+
array $globalVariables = [],
4042
): MutatingScope;
4143

4244
}

‎src/Analyser/LazyInternalScopeFactory.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public function create(
4646
bool $afterExtractCall = false,
4747
?Scope $parentScope = null,
4848
bool $nativeTypesPromoted = false,
49+
array $globalVariables = [],
4950
): MutatingScope
5051
{
5152
return new MutatingScope(
@@ -80,6 +81,7 @@ public function create(
8081
$afterExtractCall,
8182
$parentScope,
8283
$nativeTypesPromoted,
84+
$globalVariables,
8385
);
8486
}
8587

‎src/Analyser/MutatingScope.php‎

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ final class MutatingScope implements Scope
202202
* @param array<string, true> $currentlyAllowedUndefinedExpressions
203203
* @param array<string, ExpressionTypeHolder> $nativeExpressionTypes
204204
* @param list<array{MethodReflection|FunctionReflection|null, ParameterReflection|null}> $inFunctionCallsStack
205+
* @param list<string> $globalVariables
205206
*/
206207
public function __construct(
207208
private InternalScopeFactory $scopeFactory,
@@ -235,6 +236,7 @@ public function __construct(
235236
private bool $afterExtractCall = false,
236237
private ?Scope $parentScope = null,
237238
private bool $nativeTypesPromoted = false,
239+
private array $globalVariables = [],
238240
)
239241
{
240242
if ($namespace === '') {
@@ -363,6 +365,7 @@ public function rememberConstructorScope(): self
363365
$this->afterExtractCall,
364366
$this->parentScope,
365367
$this->nativeTypesPromoted,
368+
$this->globalVariables,
366369
);
367370
}
368371

@@ -441,6 +444,7 @@ public function afterExtractCall(): self
441444
true,
442445
$this->parentScope,
443446
$this->nativeTypesPromoted,
447+
$this->globalVariables,
444448
);
445449
}
446450

@@ -497,6 +501,7 @@ public function afterClearstatcacheCall(): self
497501
$this->afterExtractCall,
498502
$this->parentScope,
499503
$this->nativeTypesPromoted,
504+
$this->globalVariables,
500505
);
501506
}
502507

@@ -579,13 +584,14 @@ public function afterOpenSslCall(string $openSslFunctionName): self
579584
$this->afterExtractCall,
580585
$this->parentScope,
581586
$this->nativeTypesPromoted,
587+
$this->globalVariables,
582588
);
583589
}
584590

585591
/** @api */
586592
public function hasVariableType(string $variableName): TrinaryLogic
587593
{
588-
if ($this->isGlobalVariable($variableName)) {
594+
if ($this->isSuperGlobalVariable($variableName)) {
589595
return TrinaryLogic::createYes();
590596
}
591597

@@ -626,7 +632,7 @@ public function getVariableType(string $variableName): Type
626632

627633
$varExprString = '$' . $variableName;
628634
if (!array_key_exists($varExprString, $this->expressionTypes)) {
629-
if ($this->isGlobalVariable($variableName)) {
635+
if ($this->isSuperGlobalVariable($variableName)) {
630636
return new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType(true));
631637
}
632638
return new MixedType();
@@ -635,6 +641,18 @@ public function getVariableType(string $variableName): Type
635641
return TypeUtils::resolveLateResolvableTypes($this->expressionTypes[$varExprString]->getType());
636642
}
637643

644+
public function setVariableAsGlobal(string $variableName): self
645+
{
646+
$this->globalVariables[] = $variableName;
647+
648+
return $this;
649+
}
650+
651+
public function isGlobalVariable(string $variableName): bool
652+
{
653+
return in_array($variableName, $this->globalVariables, true);
654+
}
655+
638656
/**
639657
* @api
640658
* @return list<string>
@@ -677,7 +695,7 @@ public function getMaybeDefinedVariables(): array
677695
return $variables;
678696
}
679697

680-
private function isGlobalVariable(string $variableName): bool
698+
private function isSuperGlobalVariable(string $variableName): bool
681699
{
682700
return in_array($variableName, self::SUPERGLOBAL_VARIABLES, true);
683701
}
@@ -2762,6 +2780,7 @@ private function promoteNativeTypes(): self
27622780
$this->afterExtractCall,
27632781
$this->parentScope,
27642782
true,
2783+
$this->globalVariables,
27652784
);
27662785
}
27672786

@@ -2956,6 +2975,7 @@ public function pushInFunctionCall($reflection, ?ParameterReflection $parameter)
29562975
$this->afterExtractCall,
29572976
$this->parentScope,
29582977
$this->nativeTypesPromoted,
2978+
$this->globalVariables,
29592979
);
29602980
}
29612981

@@ -2981,6 +3001,7 @@ public function popInFunctionCall(): self
29813001
$this->afterExtractCall,
29823002
$this->parentScope,
29833003
$this->nativeTypesPromoted,
3004+
$this->globalVariables,
29843005
);
29853006
}
29863007

@@ -3572,6 +3593,7 @@ public function restoreThis(self $restoreThisScope): self
35723593
$this->afterExtractCall,
35733594
$this->parentScope,
35743595
$this->nativeTypesPromoted,
3596+
$this->globalVariables,
35753597
);
35763598
}
35773599

@@ -3635,6 +3657,7 @@ public function enterAnonymousFunction(
36353657
false,
36363658
$this,
36373659
$this->nativeTypesPromoted,
3660+
[],
36383661
);
36393662
}
36403663

@@ -3743,6 +3766,7 @@ private function enterAnonymousFunctionWithoutReflection(
37433766
false,
37443767
$this,
37453768
$this->nativeTypesPromoted,
3769+
[],
37463770
);
37473771
}
37483772

@@ -3811,6 +3835,7 @@ public function enterArrowFunction(Expr\ArrowFunction $arrowFunction, ?array $ca
38113835
$scope->afterExtractCall,
38123836
$scope->parentScope,
38133837
$this->nativeTypesPromoted,
3838+
[],
38143839
);
38153840
}
38163841

@@ -3870,6 +3895,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu
38703895
$arrowFunctionScope->afterExtractCall,
38713896
$arrowFunctionScope->parentScope,
38723897
$this->nativeTypesPromoted,
3898+
[],
38733899
);
38743900
}
38753901

@@ -4033,6 +4059,7 @@ public function enterExpressionAssign(Expr $expr): self
40334059
$this->afterExtractCall,
40344060
$this->parentScope,
40354061
$this->nativeTypesPromoted,
4062+
$this->globalVariables,
40364063
);
40374064
$scope->resolvedTypes = $this->resolvedTypes;
40384065
$scope->truthyScopes = $this->truthyScopes;
@@ -4064,6 +4091,7 @@ public function exitExpressionAssign(Expr $expr): self
40644091
$this->afterExtractCall,
40654092
$this->parentScope,
40664093
$this->nativeTypesPromoted,
4094+
$this->globalVariables,
40674095
);
40684096
$scope->resolvedTypes = $this->resolvedTypes;
40694097
$scope->truthyScopes = $this->truthyScopes;
@@ -4106,6 +4134,7 @@ public function setAllowedUndefinedExpression(Expr $expr): self
41064134
$this->afterExtractCall,
41074135
$this->parentScope,
41084136
$this->nativeTypesPromoted,
4137+
$this->globalVariables,
41094138
);
41104139
$scope->resolvedTypes = $this->resolvedTypes;
41114140
$scope->truthyScopes = $this->truthyScopes;
@@ -4137,6 +4166,7 @@ public function unsetAllowedUndefinedExpression(Expr $expr): self
41374166
$this->afterExtractCall,
41384167
$this->parentScope,
41394168
$this->nativeTypesPromoted,
4169+
$this->globalVariables,
41404170
);
41414171
$scope->resolvedTypes = $this->resolvedTypes;
41424172
$scope->truthyScopes = $this->truthyScopes;
@@ -4284,6 +4314,7 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType,
42844314
$this->afterExtractCall,
42854315
$this->parentScope,
42864316
$this->nativeTypesPromoted,
4317+
$this->globalVariables,
42874318
);
42884319

42894320
if ($expr instanceof AlwaysRememberedExpr) {
@@ -4393,6 +4424,7 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require
43934424
$this->afterExtractCall,
43944425
$this->parentScope,
43954426
$this->nativeTypesPromoted,
4427+
$this->globalVariables,
43964428
);
43974429
}
43984430

@@ -4493,6 +4525,7 @@ private function invalidateMethodsOnExpression(Expr $expressionToInvalidate): se
44934525
$this->afterExtractCall,
44944526
$this->parentScope,
44954527
$this->nativeTypesPromoted,
4528+
$this->globalVariables,
44964529
);
44974530
}
44984531

@@ -4705,6 +4738,7 @@ public function filterBySpecifiedTypes(SpecifiedTypes $specifiedTypes): self
47054738
$scope->afterExtractCall,
47064739
$scope->parentScope,
47074740
$scope->nativeTypesPromoted,
4741+
$this->globalVariables,
47084742
);
47094743
}
47104744

@@ -4732,6 +4766,7 @@ public function addConditionalExpressions(string $exprString, array $conditional
47324766
$this->afterExtractCall,
47334767
$this->parentScope,
47344768
$this->nativeTypesPromoted,
4769+
$this->globalVariables,
47354770
);
47364771
}
47374772

@@ -4762,6 +4797,7 @@ public function exitFirstLevelStatements(): self
47624797
$this->afterExtractCall,
47634798
$this->parentScope,
47644799
$this->nativeTypesPromoted,
4800+
$this->globalVariables,
47654801
);
47664802
$scope->resolvedTypes = $this->resolvedTypes;
47674803
$scope->truthyScopes = $this->truthyScopes;
@@ -4799,6 +4835,9 @@ public function mergeWith(?self $otherScope): self
47994835
$ourExpressionTypes,
48004836
$mergedExpressionTypes,
48014837
);
4838+
4839+
$mergedGlobalVariables = array_merge($this->globalVariables, $otherScope->globalVariables);
4840+
48024841
return $this->scopeFactory->create(
48034842
$this->context,
48044843
$this->isDeclareStrictTypes(),
@@ -4816,6 +4855,7 @@ public function mergeWith(?self $otherScope): self
48164855
$this->afterExtractCall && $otherScope->afterExtractCall,
48174856
$this->parentScope,
48184857
$this->nativeTypesPromoted,
4858+
$mergedGlobalVariables,
48194859
);
48204860
}
48214861

@@ -4929,7 +4969,7 @@ private function createConditionalExpressions(
49294969
private function mergeVariableHolders(array $ourVariableTypeHolders, array $theirVariableTypeHolders): array
49304970
{
49314971
$intersectedVariableTypeHolders = [];
4932-
$globalVariableCallback = fn (Node $node) => $node instanceof Variable && is_string($node->name) && $this->isGlobalVariable($node->name);
4972+
$globalVariableCallback = fn (Node $node) => $node instanceof Variable && is_string($node->name) && $this->isSuperGlobalVariable($node->name);
49334973
$nodeFinder = new NodeFinder();
49344974
foreach ($ourVariableTypeHolders as $exprString => $variableTypeHolder) {
49354975
if (isset($theirVariableTypeHolders[$exprString])) {
@@ -5020,6 +5060,7 @@ public function processFinallyScope(self $finallyScope, self $originalFinallySco
50205060
$this->afterExtractCall,
50215061
$this->parentScope,
50225062
$this->nativeTypesPromoted,
5063+
$this->globalVariables,
50235064
);
50245065
}
50255066

@@ -5115,6 +5156,7 @@ public function processClosureScope(
51155156
$this->afterExtractCall,
51165157
$this->parentScope,
51175158
$this->nativeTypesPromoted,
5159+
$this->globalVariables,
51185160
);
51195161
}
51205162

@@ -5164,6 +5206,7 @@ public function processAlwaysIterableForeachScopeWithoutPollute(self $finalScope
51645206
$this->afterExtractCall,
51655207
$this->parentScope,
51665208
$this->nativeTypesPromoted,
5209+
$this->globalVariables,
51675210
);
51685211
}
51695212

@@ -5195,6 +5238,7 @@ public function generalizeWith(self $otherScope): self
51955238
$this->afterExtractCall,
51965239
$this->parentScope,
51975240
$this->nativeTypesPromoted,
5241+
$this->globalVariables,
51985242
);
51995243
}
52005244

‎src/Analyser/NodeScopeResolver.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,6 +1966,8 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
19661966
}
19671967

19681968
$scope = $scope->assignVariable($var->name, new MixedType(), new MixedType(), TrinaryLogic::createYes());
1969+
$scope->setVariableAsGlobal($var->name);
1970+
19691971
$vars[] = $var->name;
19701972
}
19711973
$scope = $this->processVarAnnotation($scope, $vars, $stmt);

‎src/Analyser/Scope.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ public function hasVariableType(string $variableName): TrinaryLogic;
6161

6262
public function getVariableType(string $variableName): Type;
6363

64+
public function isGlobalVariable(string $variableName): bool;
65+
6466
public function canAnyVariableExist(): bool;
6567

6668
/**

‎tests/PHPStan/Analyser/data/GlobalExpressionTypeResolverExtension.php‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,34 @@
77
use PHPStan\Analyser\Scope;
88
use PHPStan\Type\BooleanType;
99
use PHPStan\Type\ExpressionTypeResolverExtension;
10+
use PHPStan\Type\IntegerType;
11+
use PHPStan\Type\StringType;
1012
use PHPStan\Type\Type;
1113

1214
class GlobalExpressionTypeResolverExtension implements ExpressionTypeResolverExtension {
1315

1416
public function getType(Expr $expr, Scope $scope): ?Type
1517
{
16-
if (!$expr instanceof Variable) {
18+
if (
19+
!$expr instanceof Variable
20+
|| !\is_string($expr->name)
21+
|| !$scope->isGlobalVariable($expr->name)
22+
) {
1723
return null;
1824
}
1925

20-
if ($expr->name === 'MY_FRAMEWORK_GLOBAL') {
26+
if ($expr->name === 'MY_GLOBAL_BOOL') {
2127
return new BooleanType();
2228
}
2329

30+
if ($expr->name === 'MY_GLOBAL_INT') {
31+
return new IntegerType();
32+
}
33+
34+
if ($expr->name === 'MY_GLOBAL_STR') {
35+
return new StringType();
36+
}
37+
2438
return null;
2539
}
2640

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /