22
33namespace PHPStan \Type \Php ;
44
5- use PhpParser \ConstExprEvaluationException ;
6- use PhpParser \ConstExprEvaluator ;
7- use PhpParser \Node \Expr ;
8- use PhpParser \Node \Expr \ConstFetch ;
95use PhpParser \Node \Expr \FuncCall ;
106use PhpParser \Node \Name \FullyQualified ;
117use PHPStan \Analyser \Scope ;
1410use PHPStan \Reflection \ReflectionProvider ;
1511use PHPStan \Type \BitwiseFlagHelper ;
1612use PHPStan \Type \Constant \ConstantBooleanType ;
17- use PHPStan \Type \Constant \ConstantIntegerType ;
1813use PHPStan \Type \Constant \ConstantStringType ;
14+ use PHPStan \Type \ConstantScalarType ;
1915use PHPStan \Type \ConstantTypeHelper ;
2016use PHPStan \Type \DynamicFunctionReturnTypeExtension ;
2117use PHPStan \Type \MixedType ;
2218use PHPStan \Type \ObjectType ;
2319use PHPStan \Type \Type ;
2420use PHPStan \Type \TypeCombinator ;
2521use stdClass ;
26- use function constant ;
2722use function is_bool ;
2823use function json_decode ;
2924
3025class JsonThrowOnErrorDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
3126{
3227
33- private const UNABLE_TO_RESOLVE = '__UNABLE_TO_RESOLVE__ ' ;
34-
35- private ConstExprEvaluator $ constExprEvaluator ;
36-
3728 /** @var array<string, int> */
3829 private array $ argumentPositions = [
3930 'json_encode ' => 1 ,
@@ -45,13 +36,6 @@ public function __construct(
4536 private BitwiseFlagHelper $ bitwiseFlagAnalyser ,
4637 )
4738 {
48- $ this ->constExprEvaluator = new ConstExprEvaluator (static function (Expr $ expr ) {
49- if ($ expr instanceof ConstFetch) {
50- return constant ($ expr ->name ->toString ());
51- }
52-
53- return null ;
54- });
5539 }
5640
5741 public function isFunctionSupported (
@@ -116,32 +100,23 @@ private function narrowTypeForJsonDecode(FuncCall $funcCall, Scope $scope): Type
116100 private function isForceArrayWithoutStdClass (FuncCall $ funcCall , Scope $ scope ): bool
117101 {
118102 $ args = $ funcCall ->getArgs ();
103+ if (!isset ($ args [1 ])) {
104+ return false ;
105+ }
119106
120- if (isset ($ args [1 ])) {
121- $ secondArgValue = $ this ->resolveMaskValue ($ args [1 ]->value , $ scope );
122- if ($ secondArgValue === self ::UNABLE_TO_RESOLVE ) {
123- return false ;
124- }
125-
126- if (is_bool ($ secondArgValue )) {
127- return $ secondArgValue ;
128- }
129-
130- // depends on used constants
131- if ($ secondArgValue === null ) {
132- if (! isset ($ args [3 ])) {
133- return false ;
134- }
135-
136- // @see https://www.php.net/manual/en/json.constants.php#constant.json-object-as-array
137- $ thirdArgValue = $ args [3 ]->value ;
138- if ($ this ->bitwiseFlagAnalyser ->bitwiseOrContainsConstant ($ thirdArgValue , $ scope , 'JSON_OBJECT_AS_ARRAY ' )->yes ()) {
139- return true ;
140- }
141- }
107+ $ secondArgType = $ scope ->getType ($ args [1 ]->value );
108+ $ secondArgValue = $ secondArgType instanceof ConstantScalarType ? $ secondArgType ->getValue () : null ;
109+
110+ if (is_bool ($ secondArgValue )) {
111+ return $ secondArgValue ;
112+ }
113+
114+ if ($ secondArgValue !== null || !isset ($ args [3 ])) {
115+ return false ;
142116 }
143117
144- return false ;
118+ // depends on used constants, @see https://www.php.net/manual/en/json.constants.php#constant.json-object-as-array
119+ return $ this ->bitwiseFlagAnalyser ->bitwiseOrContainsConstant ($ args [3 ]->value , $ scope , 'JSON_OBJECT_AS_ARRAY ' )->yes ();
145120 }
146121
147122 private function resolveConstantStringType (ConstantStringType $ constantStringType , bool $ isForceArray ): Type
@@ -151,23 +126,4 @@ private function resolveConstantStringType(ConstantStringType $constantStringTyp
151126 return ConstantTypeHelper::getTypeFromValue ($ decodedValue );
152127 }
153128
154- /**
155- * @return mixed
156- */
157- private function resolveMaskValue (Expr $ expr , Scope $ scope )
158- {
159- $ thirdArgValueType = $ scope ->getType ($ expr );
160- if ($ thirdArgValueType instanceof ConstantIntegerType) {
161- return $ thirdArgValueType ->getValue ();
162- }
163-
164- // fallback to value resolver
165- try {
166- return $ this ->constExprEvaluator ->evaluateSilently ($ expr );
167- } catch (ConstExprEvaluationException ) {
168- // unable to resolve
169- return self ::UNABLE_TO_RESOLVE ;
170- }
171- }
172-
173129}
0 commit comments