@@ -175,6 +175,8 @@ final class MutatingScope implements Scope
175175
176176 private const KEEP_VOID_ATTRIBUTE_NAME = 'keepVoid ' ;
177177
178+ private const IS_GLOBAL_ATTRIBUTE_NAME = 'isGlobal ' ;
179+
178180 /** @var Type[] */
179181 private array $ resolvedTypes = [];
180182
@@ -582,10 +584,25 @@ public function afterOpenSslCall(string $openSslFunctionName): self
582584 );
583585 }
584586
587+ /** @api */
588+ public function isGlobalVariable (string $ variableName ): bool
589+ {
590+ if ($ this ->isSuperglobalVariable ($ variableName )) {
591+ return true ;
592+ }
593+
594+ $ varExprString = '$ ' . $ variableName ;
595+ if (!isset ($ this ->expressionTypes [$ varExprString ])) {
596+ return false ;
597+ }
598+
599+ return $ this ->expressionTypes [$ varExprString ]->getExpr ()->getAttribute (self ::IS_GLOBAL_ATTRIBUTE_NAME ) === true ;
600+ }
601+
585602 /** @api */
586603 public function hasVariableType (string $ variableName ): TrinaryLogic
587604 {
588- if ($ this ->isGlobalVariable ($ variableName )) {
605+ if ($ this ->isSuperglobalVariable ($ variableName )) {
589606 return TrinaryLogic::createYes ();
590607 }
591608
@@ -626,7 +643,7 @@ public function getVariableType(string $variableName): Type
626643
627644 $ varExprString = '$ ' . $ variableName ;
628645 if (!array_key_exists ($ varExprString , $ this ->expressionTypes )) {
629- if ($ this ->isGlobalVariable ($ variableName )) {
646+ if ($ this ->isSuperglobalVariable ($ variableName )) {
630647 return new ArrayType (new BenevolentUnionType ([new IntegerType (), new StringType ()]), new MixedType (true ));
631648 }
632649 return new MixedType ();
@@ -677,7 +694,7 @@ public function getMaybeDefinedVariables(): array
677694 return $ variables ;
678695 }
679696
680- private function isGlobalVariable (string $ variableName ): bool
697+ private function isSuperglobalVariable (string $ variableName ): bool
681698 {
682699 return in_array ($ variableName , self ::SUPERGLOBAL_VARIABLES , true );
683700 }
@@ -4152,9 +4169,13 @@ public function isUndefinedExpressionAllowed(Expr $expr): bool
41524169 return array_key_exists ($ exprString , $ this ->currentlyAllowedUndefinedExpressions );
41534170 }
41544171
4155- public function assignVariable (string $ variableName , Type $ type , Type $ nativeType , TrinaryLogic $ certainty ): self
4172+ public function assignVariable (string $ variableName , Type $ type , Type $ nativeType , TrinaryLogic $ certainty, bool $ isGlobal = false ): self
41564173 {
41574174 $ node = new Variable ($ variableName );
4175+ if ($ isGlobal || $ this ->isGlobalVariable ($ variableName )) {
4176+ $ node ->setAttribute (self ::IS_GLOBAL_ATTRIBUTE_NAME , true );
4177+ }
4178+
41584179 $ scope = $ this ->assignExpression ($ node , $ type , $ nativeType );
41594180 if ($ certainty ->no ()) {
41604181 throw new ShouldNotHappenException ();
@@ -4929,7 +4950,7 @@ private function createConditionalExpressions(
49294950 private function mergeVariableHolders (array $ ourVariableTypeHolders , array $ theirVariableTypeHolders ): array
49304951 {
49314952 $ intersectedVariableTypeHolders = [];
4932- $ globalVariableCallback = fn (Node $ node ) => $ node instanceof Variable && is_string ($ node ->name ) && $ this ->isGlobalVariable ($ node ->name );
4953+ $ globalVariableCallback = fn (Node $ node ) => $ node instanceof Variable && is_string ($ node ->name ) && $ this ->isSuperglobalVariable ($ node ->name );
49334954 $ nodeFinder = new NodeFinder ();
49344955 foreach ($ ourVariableTypeHolders as $ exprString => $ variableTypeHolder ) {
49354956 if (isset ($ theirVariableTypeHolders [$ exprString ])) {
0 commit comments