@@ -182,6 +182,8 @@ final class MutatingScope implements Scope, NodeCallbackInvoker
182182
183183 private const KEEP_VOID_ATTRIBUTE_NAME = 'keepVoid ' ;
184184
185+ private const IS_GLOBAL_ATTRIBUTE_NAME = 'isGlobal ' ;
186+
185187 /** @var Type[] */
186188 private array $ resolvedTypes = [];
187189
@@ -619,10 +621,25 @@ public function afterOpenSslCall(string $openSslFunctionName): self
619621 );
620622 }
621623
624+ /** @api */
625+ public function isGlobalVariable (string $ variableName ): bool
626+ {
627+ if ($ this ->isSuperglobalVariable ($ variableName )) {
628+ return true ;
629+ }
630+
631+ $ varExprString = '$ ' . $ variableName ;
632+ if (!isset ($ this ->expressionTypes [$ varExprString ])) {
633+ return false ;
634+ }
635+
636+ return $ this ->expressionTypes [$ varExprString ]->getExpr ()->getAttribute (self ::IS_GLOBAL_ATTRIBUTE_NAME ) === true ;
637+ }
638+
622639 /** @api */
623640 public function hasVariableType (string $ variableName ): TrinaryLogic
624641 {
625- if ($ this ->isGlobalVariable ($ variableName )) {
642+ if ($ this ->isSuperglobalVariable ($ variableName )) {
626643 return TrinaryLogic::createYes ();
627644 }
628645
@@ -663,7 +680,7 @@ public function getVariableType(string $variableName): Type
663680
664681 $ varExprString = '$ ' . $ variableName ;
665682 if (!array_key_exists ($ varExprString , $ this ->expressionTypes )) {
666- if ($ this ->isGlobalVariable ($ variableName )) {
683+ if ($ this ->isSuperglobalVariable ($ variableName )) {
667684 return new ArrayType (new BenevolentUnionType ([new IntegerType (), new StringType ()]), new MixedType (true ));
668685 }
669686 return new MixedType ();
@@ -714,7 +731,7 @@ public function getMaybeDefinedVariables(): array
714731 return $ variables ;
715732 }
716733
717- private function isGlobalVariable (string $ variableName ): bool
734+ private function isSuperglobalVariable (string $ variableName ): bool
718735 {
719736 return in_array ($ variableName , self ::SUPERGLOBAL_VARIABLES , true );
720737 }
@@ -4292,9 +4309,13 @@ public function isUndefinedExpressionAllowed(Expr $expr): bool
42924309 return array_key_exists ($ exprString , $ this ->currentlyAllowedUndefinedExpressions );
42934310 }
42944311
4295- public function assignVariable (string $ variableName , Type $ type , Type $ nativeType , TrinaryLogic $ certainty ): self
4312+ public function assignVariable (string $ variableName , Type $ type , Type $ nativeType , TrinaryLogic $ certainty, bool $ isGlobal = false ): self
42964313 {
42974314 $ node = new Variable ($ variableName );
4315+ if ($ isGlobal || $ this ->isGlobalVariable ($ variableName )) {
4316+ $ node ->setAttribute (self ::IS_GLOBAL_ATTRIBUTE_NAME , true );
4317+ }
4318+
42984319 $ scope = $ this ->assignExpression ($ node , $ type , $ nativeType );
42994320 if ($ certainty ->no ()) {
43004321 throw new ShouldNotHappenException ();
@@ -5079,7 +5100,7 @@ private function createConditionalExpressions(
50795100 private function mergeVariableHolders (array $ ourVariableTypeHolders , array $ theirVariableTypeHolders ): array
50805101 {
50815102 $ intersectedVariableTypeHolders = [];
5082- $ globalVariableCallback = fn (Node $ node ) => $ node instanceof Variable && is_string ($ node ->name ) && $ this ->isGlobalVariable ($ node ->name );
5103+ $ globalVariableCallback = fn (Node $ node ) => $ node instanceof Variable && is_string ($ node ->name ) && $ this ->isSuperglobalVariable ($ node ->name );
50835104 $ nodeFinder = new NodeFinder ();
50845105 foreach ($ ourVariableTypeHolders as $ exprString => $ variableTypeHolder ) {
50855106 if (isset ($ theirVariableTypeHolders [$ exprString ])) {
0 commit comments