diff --git a/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php b/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php index 1b177d99f1d..aa864a3eac3 100644 --- a/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php +++ b/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php @@ -12,21 +12,15 @@ use PHPStan\Reflection\FunctionReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Reflection\ReflectionProvider; -use PHPStan\Type\ArrayType; -use PHPStan\Type\BooleanType; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\ConstantTypeHelper; use PHPStan\Type\DynamicFunctionReturnTypeExtension; -use PHPStan\Type\FloatType; -use PHPStan\Type\IntegerType; use PHPStan\Type\MixedType; use PHPStan\Type\ObjectType; -use PHPStan\Type\StringType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\UnionType; use stdClass; use function json_decode; @@ -66,11 +60,7 @@ public function getTypeFromFunctionCall( // narrow type for json_decode() if ($functionReflection->getName() === 'json_decode') { - $jsonDecodeNarrowedType = $this->narrowTypeForJsonDecode($functionCall, $scope); - // improve type - if (! $jsonDecodeNarrowedType instanceof MixedType) { - $defaultReturnType = $jsonDecodeNarrowedType; - } + $defaultReturnType = $this->narrowTypeForJsonDecode($functionCall, $scope); } if (!isset($functionCall->getArgs()[$argumentPosition])) { @@ -128,35 +118,15 @@ private function narrowTypeForJsonDecode(FuncCall $funcCall, Scope $scope): Type $firstValueType = $scope->getType($firstArgValue); if ($firstValueType instanceof ConstantStringType) { - $resolvedType = $this->resolveConstantStringType($firstValueType, $isForceArray); - } else { - $resolvedType = new MixedType(); - } - - // prefer specific type - if (! $resolvedType instanceof MixedType) { - return $resolvedType; + return $this->resolveConstantStringType($firstValueType, $isForceArray); } // fallback type if ($isForceArray) { - return new UnionType([ - new ArrayType(new MixedType(), new MixedType()), - new StringType(), - new FloatType(), - new IntegerType(), - new BooleanType(), - ]); + return new MixedType(true, new ObjectType(stdClass::class)); } - // scalar types with stdClass - return new UnionType([ - new ObjectType(stdClass::class), - new StringType(), - new FloatType(), - new IntegerType(), - new BooleanType(), - ]); + return new MixedType(true); } /** @@ -167,18 +137,16 @@ private function isForceArray(FuncCall $funcCall): bool { $args = $funcCall->getArgs(); - if (!isset($args[1])) { + if (! isset($args[1])) { return false; } $secondArgValue = $args[1]->value; - if ($secondArgValue instanceof ConstFetch) { - if ($secondArgValue->name->toLowerString() === 'true') { - return true; - } + if (! $secondArgValue instanceof ConstFetch) { + return false; } - return false; + return $secondArgValue->name->toLowerString() === 'true'; } private function resolveConstantStringType(ConstantStringType $constantStringType, bool $isForceArray): Type diff --git a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php index d934bc9ce62..92bdde96ae0 100644 --- a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php @@ -8749,15 +8749,15 @@ public function dataPhp73Functions(): array 'json_encode($mixed, $integer | JSON_THROW_ON_ERROR | JSON_NUMERIC_CHECK)', ], [ - 'bool|float|int|stdClass|string', + 'mixed', 'json_decode($mixed)', ], [ - 'float|int|stdClass|string|true', + 'mixed~false', 'json_decode($mixed, false, 512, JSON_THROW_ON_ERROR | JSON_NUMERIC_CHECK)', ], [ - 'float|int|stdClass|string|true', + 'mixed~false', 'json_decode($mixed, false, 512, $integer | JSON_THROW_ON_ERROR | JSON_NUMERIC_CHECK)', ], [ diff --git a/tests/PHPStan/Analyser/data/json-decode/narrow_type.php b/tests/PHPStan/Analyser/data/json-decode/narrow_type.php index 15251b69a05..e7c72b4e317 100644 --- a/tests/PHPStan/Analyser/data/json-decode/narrow_type.php +++ b/tests/PHPStan/Analyser/data/json-decode/narrow_type.php @@ -21,3 +21,9 @@ $value = json_decode('[1, 2, 3]'); assertType('array{1, 2, 3}', $value); + + +function ($mixed) { + $value = json_decode($mixed); + assertType('mixed', $value); +}; diff --git a/tests/PHPStan/Analyser/data/json-decode/narrow_type_with_force_array.php b/tests/PHPStan/Analyser/data/json-decode/narrow_type_with_force_array.php index 9aefff0540f..479085c8147 100644 --- a/tests/PHPStan/Analyser/data/json-decode/narrow_type_with_force_array.php +++ b/tests/PHPStan/Analyser/data/json-decode/narrow_type_with_force_array.php @@ -21,3 +21,8 @@ $value = json_decode('[1, 2, 3]', true); assertType('array{1, 2, 3}', $value); + +function ($mixed) { + $value = json_decode($mixed, true); + assertType('mixed~stdClass', $value); +};