@@ -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
0 commit comments