99use PHPStan \Reflection \FunctionReflection ;
1010use PHPStan \Reflection \ParametersAcceptorSelector ;
1111use PHPStan \Reflection \ReflectionProvider ;
12+ use PHPStan \TrinaryLogic ;
1213use PHPStan \Type \BitwiseFlagHelper ;
1314use PHPStan \Type \Constant \ConstantBooleanType ;
1415use PHPStan \Type \Constant \ConstantStringType ;
15- use PHPStan \Type \ConstantScalarType ;
1616use PHPStan \Type \ConstantTypeHelper ;
1717use PHPStan \Type \DynamicFunctionReturnTypeExtension ;
1818use PHPStan \Type \ObjectWithoutClassType ;
@@ -87,11 +87,17 @@ private function narrowTypeForJsonDecode(FuncCall $funcCall, Scope $scope, Type
8787 }
8888
8989 $ firstValueType = $ scope ->getType ($ args [0 ]->value );
90- if ($ firstValueType instanceof ConstantStringType) {
91- return $ this ->resolveConstantStringType ($ firstValueType , $ isForceArray );
90+ if ($ firstValueType ->getConstantStrings () !== []) {
91+ $ types = [];
92+
93+ foreach ($ firstValueType ->getConstantStrings () as $ constantString ) {
94+ $ types [] = $ this ->resolveConstantStringType ($ constantString , $ isForceArray );
95+ }
96+
97+ return TypeCombinator::union (...$ types );
9298 }
9399
94- if ($ isForceArray ) {
100+ if ($ isForceArray-> yes () ) {
95101 return TypeCombinator::remove ($ fallbackType , new ObjectWithoutClassType ());
96102 }
97103
@@ -101,33 +107,55 @@ private function narrowTypeForJsonDecode(FuncCall $funcCall, Scope $scope, Type
101107 /**
102108 * Is "json_decode(..., true)"?
103109 */
104- private function isForceArray (FuncCall $ funcCall , Scope $ scope ): bool
110+ private function isForceArray (FuncCall $ funcCall , Scope $ scope ): TrinaryLogic
105111 {
106112 $ args = $ funcCall ->getArgs ();
113+ $ flagValue = $ this ->getFlagValue ($ funcCall , $ scope );
107114 if (!isset ($ args [1 ])) {
108- return false ;
115+ return TrinaryLogic:: createNo () ;
109116 }
110117
111118 $ secondArgType = $ scope ->getType ($ args [1 ]->value );
112- $ secondArgValue = $ secondArgType instanceof ConstantScalarType ? $ secondArgType ->getValue () : null ;
119+ $ secondArgValues = [];
120+ foreach ($ secondArgType ->getConstantScalarValues () as $ value ) {
121+ if ($ value === null ) {
122+ $ secondArgValues [] = $ flagValue ;
123+ continue ;
124+ }
125+ if (!is_bool ($ value )) {
126+ return TrinaryLogic::createNo ();
127+ }
128+ $ secondArgValues [] = TrinaryLogic::createFromBoolean ($ value );
129+ }
113130
114- if (is_bool ( $ secondArgValue ) ) {
115- return $ secondArgValue ;
131+ if ($ secondArgValues === [] ) {
132+ return TrinaryLogic:: createNo () ;
116133 }
117134
118- if ($ secondArgValue !== null || !isset ($ args [3 ])) {
119- return false ;
135+ return TrinaryLogic::extremeIdentity (...$ secondArgValues );
136+ }
137+
138+ private function resolveConstantStringType (ConstantStringType $ constantStringType , TrinaryLogic $ isForceArray ): Type
139+ {
140+ $ types = [];
141+ /** @var bool $asArray */
142+ foreach ($ isForceArray ->toBooleanType ()->getConstantScalarValues () as $ asArray ) {
143+ $ decodedValue = json_decode ($ constantStringType ->getValue (), $ asArray );
144+ $ types [] = ConstantTypeHelper::getTypeFromValue ($ decodedValue );
120145 }
121146
122- // depends on used constants, @see https://www.php.net/manual/en/json.constants.php#constant.json-object-as-array
123- return $ this ->bitwiseFlagAnalyser ->bitwiseOrContainsConstant ($ args [3 ]->value , $ scope , 'JSON_OBJECT_AS_ARRAY ' )->yes ();
147+ return TypeCombinator::union (...$ types );
124148 }
125149
126- private function resolveConstantStringType ( ConstantStringType $ constantStringType , bool $ isForceArray ): Type
150+ private function getFlagValue ( FuncCall $ funcCall , Scope $ scope ): TrinaryLogic
127151 {
128- $ decodedValue = json_decode ($ constantStringType ->getValue (), $ isForceArray );
152+ $ args = $ funcCall ->getArgs ();
153+ if (!isset ($ args [3 ])) {
154+ return TrinaryLogic::createNo ();
155+ }
129156
130- return ConstantTypeHelper::getTypeFromValue ($ decodedValue );
157+ // depends on used constants, @see https://www.php.net/manual/en/json.constants.php#constant.json-object-as-array
158+ return $ this ->bitwiseFlagAnalyser ->bitwiseOrContainsConstant ($ args [3 ]->value , $ scope , 'JSON_OBJECT_AS_ARRAY ' );
131159 }
132160
133161}
0 commit comments