@@ -167,6 +167,7 @@ class MutatingScope implements Scope
167
167
* @param VariableTypeHolder[] $moreSpecificTypes
168
168
* @param array<string, ConditionalExpressionHolder[]> $conditionalExpressions
169
169
* @param array<string, true> $currentlyAssignedExpressions
170
+ * @param array<string, bool> $currentlyAllowedUndefinedExpressions
170
171
* @param array<string, Type> $nativeExpressionTypes
171
172
* @param array<MethodReflection|FunctionReflection> $inFunctionCallsStack
172
173
* @param string[] $dynamicConstantNames
@@ -194,6 +195,7 @@ public function __construct(
194
195
private ?ParametersAcceptor $ anonymousFunctionReflection = null ,
195
196
private bool $ inFirstLevelStatement = true ,
196
197
private array $ currentlyAssignedExpressions = [],
198
+ private array $ currentlyAllowedUndefinedExpressions = [],
197
199
private array $ nativeExpressionTypes = [],
198
200
private array $ inFunctionCallsStack = [],
199
201
private array $ dynamicConstantNames = [],
@@ -341,6 +343,7 @@ public function afterExtractCall(): self
341
343
$ this ->anonymousFunctionReflection ,
342
344
$ this ->isInFirstLevelStatement (),
343
345
$ this ->currentlyAssignedExpressions ,
346
+ $ this ->currentlyAllowedUndefinedExpressions ,
344
347
$ this ->nativeExpressionTypes ,
345
348
$ this ->inFunctionCallsStack ,
346
349
true ,
@@ -397,6 +400,7 @@ public function afterClearstatcacheCall(): self
397
400
$ this ->anonymousFunctionReflection ,
398
401
$ this ->isInFirstLevelStatement (),
399
402
$ this ->currentlyAssignedExpressions ,
403
+ $ this ->currentlyAllowedUndefinedExpressions ,
400
404
$ this ->nativeExpressionTypes ,
401
405
$ this ->inFunctionCallsStack ,
402
406
$ this ->afterExtractCall ,
@@ -3016,6 +3020,7 @@ public function doNotTreatPhpDocTypesAsCertain(): Scope
3016
3020
$ this ->anonymousFunctionReflection ,
3017
3021
$ this ->inFirstLevelStatement ,
3018
3022
$ this ->currentlyAssignedExpressions ,
3023
+ $ this ->currentlyAllowedUndefinedExpressions ,
3019
3024
$ this ->nativeExpressionTypes ,
3020
3025
$ this ->inFunctionCallsStack ,
3021
3026
$ this ->dynamicConstantNames ,
@@ -3056,6 +3061,7 @@ private function promoteNativeTypes(): self
3056
3061
$ this ->anonymousFunctionReflection ,
3057
3062
$ this ->inFirstLevelStatement ,
3058
3063
$ this ->currentlyAssignedExpressions ,
3064
+ $ this ->currentlyAllowedUndefinedExpressions ,
3059
3065
[],
3060
3066
);
3061
3067
}
@@ -3315,6 +3321,7 @@ public function pushInFunctionCall($reflection): self
3315
3321
$ this ->anonymousFunctionReflection ,
3316
3322
$ this ->isInFirstLevelStatement (),
3317
3323
$ this ->currentlyAssignedExpressions ,
3324
+ $ this ->currentlyAllowedUndefinedExpressions ,
3318
3325
$ this ->nativeExpressionTypes ,
3319
3326
$ stack ,
3320
3327
$ this ->afterExtractCall ,
@@ -3340,6 +3347,7 @@ public function popInFunctionCall(): self
3340
3347
$ this ->anonymousFunctionReflection ,
3341
3348
$ this ->isInFirstLevelStatement (),
3342
3349
$ this ->currentlyAssignedExpressions ,
3350
+ $ this ->currentlyAllowedUndefinedExpressions ,
3343
3351
$ this ->nativeExpressionTypes ,
3344
3352
$ stack ,
3345
3353
$ this ->afterExtractCall ,
@@ -3596,6 +3604,7 @@ private function enterFunctionLike(
3596
3604
null ,
3597
3605
true ,
3598
3606
[],
3607
+ [],
3599
3608
$ nativeExpressionTypes ,
3600
3609
);
3601
3610
}
@@ -3716,6 +3725,7 @@ public function enterAnonymousFunction(
3716
3725
$ anonymousFunctionReflection ,
3717
3726
true ,
3718
3727
[],
3728
+ [],
3719
3729
$ scope ->nativeExpressionTypes ,
3720
3730
[],
3721
3731
false ,
@@ -3807,6 +3817,7 @@ private function enterAnonymousFunctionWithoutReflection(
3807
3817
new TrivialParametersAcceptor (),
3808
3818
true ,
3809
3819
[],
3820
+ [],
3810
3821
$ nativeTypes ,
3811
3822
[],
3812
3823
false ,
@@ -3842,6 +3853,7 @@ public function enterArrowFunction(Expr\ArrowFunction $arrowFunction, ?array $ca
3842
3853
[],
3843
3854
[],
3844
3855
[],
3856
+ [],
3845
3857
$ scope ->afterExtractCall ,
3846
3858
$ scope ->parentScope ,
3847
3859
);
@@ -3962,6 +3974,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu
3962
3974
[],
3963
3975
[],
3964
3976
[],
3977
+ [],
3965
3978
$ this ->afterExtractCall ,
3966
3979
$ this ->parentScope ,
3967
3980
);
@@ -4089,6 +4102,7 @@ public function enterExpressionAssign(Expr $expr): self
4089
4102
$ this ->anonymousFunctionReflection ,
4090
4103
$ this ->isInFirstLevelStatement (),
4091
4104
$ currentlyAssignedExpressions ,
4105
+ $ this ->currentlyAllowedUndefinedExpressions ,
4092
4106
$ this ->nativeExpressionTypes ,
4093
4107
[],
4094
4108
$ this ->afterExtractCall ,
@@ -4115,6 +4129,7 @@ public function exitExpressionAssign(Expr $expr): self
4115
4129
$ this ->anonymousFunctionReflection ,
4116
4130
$ this ->isInFirstLevelStatement (),
4117
4131
$ currentlyAssignedExpressions ,
4132
+ $ this ->currentlyAllowedUndefinedExpressions ,
4118
4133
$ this ->nativeExpressionTypes ,
4119
4134
[],
4120
4135
$ this ->afterExtractCall ,
@@ -4129,6 +4144,70 @@ public function isInExpressionAssign(Expr $expr): bool
4129
4144
return array_key_exists ($ exprString , $ this ->currentlyAssignedExpressions );
4130
4145
}
4131
4146
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
+
4132
4211
public function assignVariable (string $ variableName , Type $ type , ?TrinaryLogic $ certainty = null ): self
4133
4212
{
4134
4213
if ($ certainty === null ) {
@@ -4191,6 +4270,7 @@ public function assignVariable(string $variableName, Type $type, ?TrinaryLogic $
4191
4270
$ this ->anonymousFunctionReflection ,
4192
4271
$ this ->inFirstLevelStatement ,
4193
4272
$ this ->currentlyAssignedExpressions ,
4273
+ $ this ->currentlyAllowedUndefinedExpressions ,
4194
4274
$ nativeTypes ,
4195
4275
$ this ->inFunctionCallsStack ,
4196
4276
$ this ->afterExtractCall ,
@@ -4227,6 +4307,7 @@ public function unsetExpression(Expr $expr): self
4227
4307
$ this ->anonymousFunctionReflection ,
4228
4308
$ this ->inFirstLevelStatement ,
4229
4309
[],
4310
+ [],
4230
4311
$ nativeTypes ,
4231
4312
[],
4232
4313
$ this ->afterExtractCall ,
@@ -4270,6 +4351,7 @@ public function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType
4270
4351
$ this ->anonymousFunctionReflection ,
4271
4352
$ this ->inFirstLevelStatement ,
4272
4353
$ this ->currentlyAssignedExpressions ,
4354
+ $ this ->currentlyAllowedUndefinedExpressions ,
4273
4355
$ this ->nativeExpressionTypes ,
4274
4356
$ this ->inFunctionCallsStack ,
4275
4357
$ this ->afterExtractCall ,
@@ -4308,6 +4390,7 @@ public function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType
4308
4390
$ this ->anonymousFunctionReflection ,
4309
4391
$ this ->inFirstLevelStatement ,
4310
4392
$ this ->currentlyAssignedExpressions ,
4393
+ $ this ->currentlyAllowedUndefinedExpressions ,
4311
4394
$ nativeTypes ,
4312
4395
$ this ->inFunctionCallsStack ,
4313
4396
$ this ->afterExtractCall ,
@@ -4425,6 +4508,7 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require
4425
4508
$ this ->anonymousFunctionReflection ,
4426
4509
$ this ->inFirstLevelStatement ,
4427
4510
$ this ->currentlyAssignedExpressions ,
4511
+ $ this ->currentlyAllowedUndefinedExpressions ,
4428
4512
$ nativeExpressionTypes ,
4429
4513
[],
4430
4514
$ this ->afterExtractCall ,
@@ -4483,6 +4567,7 @@ public function invalidateMethodsOnExpression(Expr $expressionToInvalidate): sel
4483
4567
$ this ->anonymousFunctionReflection ,
4484
4568
$ this ->inFirstLevelStatement ,
4485
4569
$ this ->currentlyAssignedExpressions ,
4570
+ $ this ->currentlyAllowedUndefinedExpressions ,
4486
4571
$ nativeExpressionTypes ,
4487
4572
[],
4488
4573
$ this ->afterExtractCall ,
@@ -4700,6 +4785,7 @@ public function changeConditionalExpressions(array $newConditionalExpressionHold
4700
4785
$ this ->anonymousFunctionReflection ,
4701
4786
$ this ->inFirstLevelStatement ,
4702
4787
$ this ->currentlyAssignedExpressions ,
4788
+ $ this ->currentlyAllowedUndefinedExpressions ,
4703
4789
$ this ->nativeExpressionTypes ,
4704
4790
$ this ->inFunctionCallsStack ,
4705
4791
$ this ->afterExtractCall ,
@@ -4727,6 +4813,7 @@ public function addConditionalExpressions(string $exprString, array $conditional
4727
4813
$ this ->anonymousFunctionReflection ,
4728
4814
$ this ->inFirstLevelStatement ,
4729
4815
$ this ->currentlyAssignedExpressions ,
4816
+ $ this ->currentlyAllowedUndefinedExpressions ,
4730
4817
$ this ->nativeExpressionTypes ,
4731
4818
$ this ->inFunctionCallsStack ,
4732
4819
$ this ->afterExtractCall ,
@@ -4749,6 +4836,7 @@ public function exitFirstLevelStatements(): self
4749
4836
$ this ->anonymousFunctionReflection ,
4750
4837
false ,
4751
4838
$ this ->currentlyAssignedExpressions ,
4839
+ $ this ->currentlyAllowedUndefinedExpressions ,
4752
4840
$ this ->nativeExpressionTypes ,
4753
4841
$ this ->inFunctionCallsStack ,
4754
4842
$ this ->afterExtractCall ,
@@ -4786,6 +4874,7 @@ private function addMoreSpecificTypes(array $types): self
4786
4874
$ this ->anonymousFunctionReflection ,
4787
4875
$ this ->inFirstLevelStatement ,
4788
4876
$ this ->currentlyAssignedExpressions ,
4877
+ $ this ->currentlyAllowedUndefinedExpressions ,
4789
4878
$ this ->nativeExpressionTypes ,
4790
4879
[],
4791
4880
$ this ->afterExtractCall ,
@@ -4854,6 +4943,7 @@ public function mergeWith(?self $otherScope): self
4854
4943
$ this ->anonymousFunctionReflection ,
4855
4944
$ this ->inFirstLevelStatement ,
4856
4945
[],
4946
+ [],
4857
4947
array_map ($ variableHolderToType , array_filter ($ this ->mergeVariableHolders (
4858
4948
array_map ($ typeToVariableHolder , $ this ->nativeExpressionTypes ),
4859
4949
array_map ($ typeToVariableHolder , $ otherScope ->nativeExpressionTypes ),
@@ -5025,6 +5115,7 @@ public function processFinallyScope(self $finallyScope, self $originalFinallySco
5025
5115
$ this ->anonymousFunctionReflection ,
5026
5116
$ this ->inFirstLevelStatement ,
5027
5117
[],
5118
+ [],
5028
5119
array_map ($ variableHolderToType , array_filter ($ this ->processFinallyScopeVariableTypeHolders (
5029
5120
array_map ($ typeToVariableHolder , $ this ->nativeExpressionTypes ),
5030
5121
array_map ($ typeToVariableHolder , $ finallyScope ->nativeExpressionTypes ),
@@ -5122,6 +5213,7 @@ public function processClosureScope(
5122
5213
$ this ->anonymousFunctionReflection ,
5123
5214
$ this ->inFirstLevelStatement ,
5124
5215
[],
5216
+ [],
5125
5217
$ nativeExpressionTypes ,
5126
5218
$ this ->inFunctionCallsStack ,
5127
5219
$ this ->afterExtractCall ,
@@ -5172,6 +5264,7 @@ public function processAlwaysIterableForeachScopeWithoutPollute(self $finalScope
5172
5264
$ this ->anonymousFunctionReflection ,
5173
5265
$ this ->inFirstLevelStatement ,
5174
5266
[],
5267
+ [],
5175
5268
$ nativeTypes ,
5176
5269
[],
5177
5270
$ this ->afterExtractCall ,
@@ -5215,6 +5308,7 @@ public function generalizeWith(self $otherScope): self
5215
5308
$ this ->anonymousFunctionReflection ,
5216
5309
$ this ->inFirstLevelStatement ,
5217
5310
[],
5311
+ [],
5218
5312
$ nativeTypes ,
5219
5313
[],
5220
5314
$ this ->afterExtractCall ,
0 commit comments