@@ -177,6 +177,8 @@ final class MutatingScope implements Scope
177177
178178 private const KEEP_VOID_ATTRIBUTE_NAME = 'keepVoid ' ;
179179
180+ private const IS_GLOBAL_ATTRIBUTE_NAME = 'isGlobal ' ;
181+ 180182 /** @var Type[] */
181183 private array $ resolvedTypes = [];
182184
@@ -584,10 +586,25 @@ public function afterOpenSslCall(string $openSslFunctionName): self
584586 );
585587 }
586588
589+ /** @api */
590+ public function isGlobalVariable (string $ variableName ): bool
591+ {
592+ if ($ this ->isSuperglobalVariable ($ variableName )) {
593+ return true ;
594+ }
595+ 596+ $ varExprString = '$ ' . $ variableName ;
597+ if (!isset ($ this ->expressionTypes [$ varExprString ])) {
598+ return false ;
599+ }
600+ 601+ return $ this ->expressionTypes [$ varExprString ]->getExpr ()->getAttribute (self ::IS_GLOBAL_ATTRIBUTE_NAME ) === true ;
602+ }
603+ 587604 /** @api */
588605 public function hasVariableType (string $ variableName ): TrinaryLogic
589606 {
590- if ($ this ->isGlobalVariable ($ variableName )) {
607+ if ($ this ->isSuperglobalVariable ($ variableName )) {
591608 return TrinaryLogic::createYes ();
592609 }
593610
@@ -628,7 +645,7 @@ public function getVariableType(string $variableName): Type
628645
629646 $ varExprString = '$ ' . $ variableName ;
630647 if (!array_key_exists ($ varExprString , $ this ->expressionTypes )) {
631- if ($ this ->isGlobalVariable ($ variableName )) {
648+ if ($ this ->isSuperglobalVariable ($ variableName )) {
632649 return new ArrayType (new BenevolentUnionType ([new IntegerType (), new StringType ()]), new MixedType (true ));
633650 }
634651 return new MixedType ();
@@ -679,7 +696,7 @@ public function getMaybeDefinedVariables(): array
679696 return $ variables ;
680697 }
681698
682- private function isGlobalVariable (string $ variableName ): bool
699+ private function isSuperglobalVariable (string $ variableName ): bool
683700 {
684701 return in_array ($ variableName , self ::SUPERGLOBAL_VARIABLES , true );
685702 }
@@ -4168,9 +4185,13 @@ public function isUndefinedExpressionAllowed(Expr $expr): bool
41684185 return array_key_exists ($ exprString , $ this ->currentlyAllowedUndefinedExpressions );
41694186 }
41704187
4171- public function assignVariable (string $ variableName , Type $ type , Type $ nativeType , TrinaryLogic $ certainty ): self
4188+ public function assignVariable (string $ variableName , Type $ type , Type $ nativeType , TrinaryLogic $ certainty, bool $ isGlobal = false ): self
41724189 {
41734190 $ node = new Variable ($ variableName );
4191+ if ($ isGlobal || $ this ->isGlobalVariable ($ variableName )) {
4192+ $ node ->setAttribute (self ::IS_GLOBAL_ATTRIBUTE_NAME , true );
4193+ }
4194+ 41744195 $ scope = $ this ->assignExpression ($ node , $ type , $ nativeType );
41754196 if ($ certainty ->no ()) {
41764197 throw new ShouldNotHappenException ();
@@ -4945,7 +4966,7 @@ private function createConditionalExpressions(
49454966 private function mergeVariableHolders (array $ ourVariableTypeHolders , array $ theirVariableTypeHolders ): array
49464967 {
49474968 $ intersectedVariableTypeHolders = [];
4948- $ globalVariableCallback = fn (Node $ node ) => $ node instanceof Variable && is_string ($ node ->name ) && $ this ->isGlobalVariable ($ node ->name );
4969+ $ globalVariableCallback = fn (Node $ node ) => $ node instanceof Variable && is_string ($ node ->name ) && $ this ->isSuperglobalVariable ($ node ->name );
49494970 $ nodeFinder = new NodeFinder ();
49504971 foreach ($ ourVariableTypeHolders as $ exprString => $ variableTypeHolder ) {
49514972 if (isset ($ theirVariableTypeHolders [$ exprString ])) {
0 commit comments