@@ -167,6 +167,7 @@ class MutatingScope implements Scope
167167 * @param VariableTypeHolder[] $moreSpecificTypes
168168 * @param array<string, ConditionalExpressionHolder[]> $conditionalExpressions
169169 * @param array<string, true> $currentlyAssignedExpressions
170+ * @param array<string, bool> $currentlyAllowedUndefinedExpressions
170171 * @param array<string, Type> $nativeExpressionTypes
171172 * @param array<MethodReflection|FunctionReflection> $inFunctionCallsStack
172173 * @param string[] $dynamicConstantNames
@@ -194,6 +195,7 @@ public function __construct(
194195 private ?ParametersAcceptor $ anonymousFunctionReflection = null ,
195196 private bool $ inFirstLevelStatement = true ,
196197 private array $ currentlyAssignedExpressions = [],
198+ private array $ currentlyAllowedUndefinedExpressions = [],
197199 private array $ nativeExpressionTypes = [],
198200 private array $ inFunctionCallsStack = [],
199201 private array $ dynamicConstantNames = [],
@@ -341,6 +343,7 @@ public function afterExtractCall(): self
341343 $ this ->anonymousFunctionReflection ,
342344 $ this ->isInFirstLevelStatement (),
343345 $ this ->currentlyAssignedExpressions ,
346+ $ this ->currentlyAllowedUndefinedExpressions ,
344347 $ this ->nativeExpressionTypes ,
345348 $ this ->inFunctionCallsStack ,
346349 true ,
@@ -397,6 +400,7 @@ public function afterClearstatcacheCall(): self
397400 $ this ->anonymousFunctionReflection ,
398401 $ this ->isInFirstLevelStatement (),
399402 $ this ->currentlyAssignedExpressions ,
403+ $ this ->currentlyAllowedUndefinedExpressions ,
400404 $ this ->nativeExpressionTypes ,
401405 $ this ->inFunctionCallsStack ,
402406 $ this ->afterExtractCall ,
@@ -3016,6 +3020,7 @@ public function doNotTreatPhpDocTypesAsCertain(): Scope
30163020 $ this ->anonymousFunctionReflection ,
30173021 $ this ->inFirstLevelStatement ,
30183022 $ this ->currentlyAssignedExpressions ,
3023+ $ this ->currentlyAllowedUndefinedExpressions ,
30193024 $ this ->nativeExpressionTypes ,
30203025 $ this ->inFunctionCallsStack ,
30213026 $ this ->dynamicConstantNames ,
@@ -3056,6 +3061,7 @@ private function promoteNativeTypes(): self
30563061 $ this ->anonymousFunctionReflection ,
30573062 $ this ->inFirstLevelStatement ,
30583063 $ this ->currentlyAssignedExpressions ,
3064+ $ this ->currentlyAllowedUndefinedExpressions ,
30593065 [],
30603066 );
30613067 }
@@ -3315,6 +3321,7 @@ public function pushInFunctionCall($reflection): self
33153321 $ this ->anonymousFunctionReflection ,
33163322 $ this ->isInFirstLevelStatement (),
33173323 $ this ->currentlyAssignedExpressions ,
3324+ $ this ->currentlyAllowedUndefinedExpressions ,
33183325 $ this ->nativeExpressionTypes ,
33193326 $ stack ,
33203327 $ this ->afterExtractCall ,
@@ -3340,6 +3347,7 @@ public function popInFunctionCall(): self
33403347 $ this ->anonymousFunctionReflection ,
33413348 $ this ->isInFirstLevelStatement (),
33423349 $ this ->currentlyAssignedExpressions ,
3350+ $ this ->currentlyAllowedUndefinedExpressions ,
33433351 $ this ->nativeExpressionTypes ,
33443352 $ stack ,
33453353 $ this ->afterExtractCall ,
@@ -3596,6 +3604,7 @@ private function enterFunctionLike(
35963604 null ,
35973605 true ,
35983606 [],
3607+ [],
35993608 $ nativeExpressionTypes ,
36003609 );
36013610 }
@@ -3716,6 +3725,7 @@ public function enterAnonymousFunction(
37163725 $ anonymousFunctionReflection ,
37173726 true ,
37183727 [],
3728+ [],
37193729 $ scope ->nativeExpressionTypes ,
37203730 [],
37213731 false ,
@@ -3807,6 +3817,7 @@ private function enterAnonymousFunctionWithoutReflection(
38073817 new TrivialParametersAcceptor (),
38083818 true ,
38093819 [],
3820+ [],
38103821 $ nativeTypes ,
38113822 [],
38123823 false ,
@@ -3842,6 +3853,7 @@ public function enterArrowFunction(Expr\ArrowFunction $arrowFunction, ?array $ca
38423853 [],
38433854 [],
38443855 [],
3856+ [],
38453857 $ scope ->afterExtractCall ,
38463858 $ scope ->parentScope ,
38473859 );
@@ -3962,6 +3974,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu
39623974 [],
39633975 [],
39643976 [],
3977+ [],
39653978 $ this ->afterExtractCall ,
39663979 $ this ->parentScope ,
39673980 );
@@ -4089,6 +4102,7 @@ public function enterExpressionAssign(Expr $expr): self
40894102 $ this ->anonymousFunctionReflection ,
40904103 $ this ->isInFirstLevelStatement (),
40914104 $ currentlyAssignedExpressions ,
4105+ $ this ->currentlyAllowedUndefinedExpressions ,
40924106 $ this ->nativeExpressionTypes ,
40934107 [],
40944108 $ this ->afterExtractCall ,
@@ -4115,6 +4129,7 @@ public function exitExpressionAssign(Expr $expr): self
41154129 $ this ->anonymousFunctionReflection ,
41164130 $ this ->isInFirstLevelStatement (),
41174131 $ currentlyAssignedExpressions ,
4132+ $ this ->currentlyAllowedUndefinedExpressions ,
41184133 $ this ->nativeExpressionTypes ,
41194134 [],
41204135 $ this ->afterExtractCall ,
@@ -4129,6 +4144,70 @@ public function isInExpressionAssign(Expr $expr): bool
41294144 return array_key_exists ($ exprString , $ this ->currentlyAssignedExpressions );
41304145 }
41314146
4147+ public function setAllowedUndefinedExpression (Expr $ expr , bool $ isAllowed ): self
4148+ {
4149+ $ exprString = $ this ->getNodeKey ($ expr );
4150+ if (array_key_exists ($ exprString , $ this ->currentlyAllowedUndefinedExpressions )) {
4151+ return $ this ;
4152+ }
4153+ $ currentlyAllowedUndefinedExpressions = $ this ->currentlyAllowedUndefinedExpressions ;
4154+ $ currentlyAllowedUndefinedExpressions [$ exprString ] = $ isAllowed ;
4155+
4156+ return $ this ->scopeFactory ->create (
4157+ $ this ->context ,
4158+ $ this ->isDeclareStrictTypes (),
4159+ $ this ->constantTypes ,
4160+ $ this ->getFunction (),
4161+ $ this ->getNamespace (),
4162+ $ this ->getVariableTypes (),
4163+ $ this ->moreSpecificTypes ,
4164+ $ this ->conditionalExpressions ,
4165+ $ this ->inClosureBindScopeClass ,
4166+ $ this ->anonymousFunctionReflection ,
4167+ $ this ->isInFirstLevelStatement (),
4168+ $ this ->currentlyAssignedExpressions ,
4169+ $ currentlyAllowedUndefinedExpressions ,
4170+ $ this ->nativeExpressionTypes ,
4171+ [],
4172+ $ this ->afterExtractCall ,
4173+ $ this ->parentScope ,
4174+ );
4175+ }
4176+
4177+ public function unsetAllowedUndefinedExpression (Expr $ expr ): self
4178+ {
4179+ $ exprString = $ this ->getNodeKey ($ expr );
4180+ $ currentlyAllowedUndefinedExpressions = $ this ->currentlyAllowedUndefinedExpressions ;
4181+ unset($ currentlyAllowedUndefinedExpressions [$ exprString ]);
4182+
4183+ return $ this ->scopeFactory ->create (
4184+ $ this ->context ,
4185+ $ this ->isDeclareStrictTypes (),
4186+ $ this ->constantTypes ,
4187+ $ this ->getFunction (),
4188+ $ this ->getNamespace (),
4189+ $ this ->getVariableTypes (),
4190+ $ this ->moreSpecificTypes ,
4191+ $ this ->conditionalExpressions ,
4192+ $ this ->inClosureBindScopeClass ,
4193+ $ this ->anonymousFunctionReflection ,
4194+ $ this ->isInFirstLevelStatement (),
4195+ $ this ->currentlyAssignedExpressions ,
4196+ $ currentlyAllowedUndefinedExpressions ,
4197+ $ this ->nativeExpressionTypes ,
4198+ [],
4199+ $ this ->afterExtractCall ,
4200+ $ this ->parentScope ,
4201+ );
4202+ }
4203+
4204+ /** @api */
4205+ public function isUndefinedExpressionAllowed (Expr $ expr ): bool
4206+ {
4207+ $ exprString = $ this ->getNodeKey ($ expr );
4208+ return array_key_exists ($ exprString , $ this ->currentlyAllowedUndefinedExpressions ) && $ this ->currentlyAllowedUndefinedExpressions [$ exprString ];
4209+ }
4210+
41324211 public function assignVariable (string $ variableName , Type $ type , ?TrinaryLogic $ certainty = null ): self
41334212 {
41344213 if ($ certainty === null ) {
@@ -4191,6 +4270,7 @@ public function assignVariable(string $variableName, Type $type, ?TrinaryLogic $
41914270 $ this ->anonymousFunctionReflection ,
41924271 $ this ->inFirstLevelStatement ,
41934272 $ this ->currentlyAssignedExpressions ,
4273+ $ this ->currentlyAllowedUndefinedExpressions ,
41944274 $ nativeTypes ,
41954275 $ this ->inFunctionCallsStack ,
41964276 $ this ->afterExtractCall ,
@@ -4227,6 +4307,7 @@ public function unsetExpression(Expr $expr): self
42274307 $ this ->anonymousFunctionReflection ,
42284308 $ this ->inFirstLevelStatement ,
42294309 [],
4310+ [],
42304311 $ nativeTypes ,
42314312 [],
42324313 $ this ->afterExtractCall ,
@@ -4270,6 +4351,7 @@ public function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType
42704351 $ this ->anonymousFunctionReflection ,
42714352 $ this ->inFirstLevelStatement ,
42724353 $ this ->currentlyAssignedExpressions ,
4354+ $ this ->currentlyAllowedUndefinedExpressions ,
42734355 $ this ->nativeExpressionTypes ,
42744356 $ this ->inFunctionCallsStack ,
42754357 $ this ->afterExtractCall ,
@@ -4308,6 +4390,7 @@ public function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType
43084390 $ this ->anonymousFunctionReflection ,
43094391 $ this ->inFirstLevelStatement ,
43104392 $ this ->currentlyAssignedExpressions ,
4393+ $ this ->currentlyAllowedUndefinedExpressions ,
43114394 $ nativeTypes ,
43124395 $ this ->inFunctionCallsStack ,
43134396 $ this ->afterExtractCall ,
@@ -4425,6 +4508,7 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require
44254508 $ this ->anonymousFunctionReflection ,
44264509 $ this ->inFirstLevelStatement ,
44274510 $ this ->currentlyAssignedExpressions ,
4511+ $ this ->currentlyAllowedUndefinedExpressions ,
44284512 $ nativeExpressionTypes ,
44294513 [],
44304514 $ this ->afterExtractCall ,
@@ -4483,6 +4567,7 @@ public function invalidateMethodsOnExpression(Expr $expressionToInvalidate): sel
44834567 $ this ->anonymousFunctionReflection ,
44844568 $ this ->inFirstLevelStatement ,
44854569 $ this ->currentlyAssignedExpressions ,
4570+ $ this ->currentlyAllowedUndefinedExpressions ,
44864571 $ nativeExpressionTypes ,
44874572 [],
44884573 $ this ->afterExtractCall ,
@@ -4700,6 +4785,7 @@ public function changeConditionalExpressions(array $newConditionalExpressionHold
47004785 $ this ->anonymousFunctionReflection ,
47014786 $ this ->inFirstLevelStatement ,
47024787 $ this ->currentlyAssignedExpressions ,
4788+ $ this ->currentlyAllowedUndefinedExpressions ,
47034789 $ this ->nativeExpressionTypes ,
47044790 $ this ->inFunctionCallsStack ,
47054791 $ this ->afterExtractCall ,
@@ -4727,6 +4813,7 @@ public function addConditionalExpressions(string $exprString, array $conditional
47274813 $ this ->anonymousFunctionReflection ,
47284814 $ this ->inFirstLevelStatement ,
47294815 $ this ->currentlyAssignedExpressions ,
4816+ $ this ->currentlyAllowedUndefinedExpressions ,
47304817 $ this ->nativeExpressionTypes ,
47314818 $ this ->inFunctionCallsStack ,
47324819 $ this ->afterExtractCall ,
@@ -4749,6 +4836,7 @@ public function exitFirstLevelStatements(): self
47494836 $ this ->anonymousFunctionReflection ,
47504837 false ,
47514838 $ this ->currentlyAssignedExpressions ,
4839+ $ this ->currentlyAllowedUndefinedExpressions ,
47524840 $ this ->nativeExpressionTypes ,
47534841 $ this ->inFunctionCallsStack ,
47544842 $ this ->afterExtractCall ,
@@ -4786,6 +4874,7 @@ private function addMoreSpecificTypes(array $types): self
47864874 $ this ->anonymousFunctionReflection ,
47874875 $ this ->inFirstLevelStatement ,
47884876 $ this ->currentlyAssignedExpressions ,
4877+ $ this ->currentlyAllowedUndefinedExpressions ,
47894878 $ this ->nativeExpressionTypes ,
47904879 [],
47914880 $ this ->afterExtractCall ,
@@ -4854,6 +4943,7 @@ public function mergeWith(?self $otherScope): self
48544943 $ this ->anonymousFunctionReflection ,
48554944 $ this ->inFirstLevelStatement ,
48564945 [],
4946+ [],
48574947 array_map ($ variableHolderToType , array_filter ($ this ->mergeVariableHolders (
48584948 array_map ($ typeToVariableHolder , $ this ->nativeExpressionTypes ),
48594949 array_map ($ typeToVariableHolder , $ otherScope ->nativeExpressionTypes ),
@@ -5025,6 +5115,7 @@ public function processFinallyScope(self $finallyScope, self $originalFinallySco
50255115 $ this ->anonymousFunctionReflection ,
50265116 $ this ->inFirstLevelStatement ,
50275117 [],
5118+ [],
50285119 array_map ($ variableHolderToType , array_filter ($ this ->processFinallyScopeVariableTypeHolders (
50295120 array_map ($ typeToVariableHolder , $ this ->nativeExpressionTypes ),
50305121 array_map ($ typeToVariableHolder , $ finallyScope ->nativeExpressionTypes ),
@@ -5122,6 +5213,7 @@ public function processClosureScope(
51225213 $ this ->anonymousFunctionReflection ,
51235214 $ this ->inFirstLevelStatement ,
51245215 [],
5216+ [],
51255217 $ nativeExpressionTypes ,
51265218 $ this ->inFunctionCallsStack ,
51275219 $ this ->afterExtractCall ,
@@ -5172,6 +5264,7 @@ public function processAlwaysIterableForeachScopeWithoutPollute(self $finalScope
51725264 $ this ->anonymousFunctionReflection ,
51735265 $ this ->inFirstLevelStatement ,
51745266 [],
5267+ [],
51755268 $ nativeTypes ,
51765269 [],
51775270 $ this ->afterExtractCall ,
@@ -5215,6 +5308,7 @@ public function generalizeWith(self $otherScope): self
52155308 $ this ->anonymousFunctionReflection ,
52165309 $ this ->inFirstLevelStatement ,
52175310 [],
5311+ [],
52185312 $ nativeTypes ,
52195313 [],
52205314 $ this ->afterExtractCall ,
0 commit comments