diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 47101ea9fe..6410adeabf 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1599,18 +1599,6 @@ parameters: count: 2 path: src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php - - - message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' - identifier: phpstanApi.instanceofType - count: 1 - path: src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php - - - - message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' - identifier: phpstanApi.instanceofType - count: 1 - path: src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php - - message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' identifier: phpstanApi.instanceofType diff --git a/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php b/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php index f9e551cc8a..79841125a0 100644 --- a/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php +++ b/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php @@ -12,12 +12,12 @@ use PHPStan\Type\BitwiseFlagHelper; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantStringType; -use PHPStan\Type\ConstantScalarType; use PHPStan\Type\ConstantTypeHelper; use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\ObjectWithoutClassType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; +use function count; use function is_bool; use function json_decode; @@ -87,8 +87,14 @@ private function narrowTypeForJsonDecode(FuncCall $funcCall, Scope $scope, Type } $firstValueType = $scope->getType($args[0]->value); - if ($firstValueType instanceof ConstantStringType) { - return $this->resolveConstantStringType($firstValueType, $isForceArray); + if ($firstValueType->getConstantStrings() !== []) { + $types = []; + + foreach ($firstValueType->getConstantStrings() as $constantString) { + $types[] = $this->resolveConstantStringType($constantString, $isForceArray); + } + + return TypeCombinator::union(...$types); } if ($isForceArray) { @@ -109,7 +115,7 @@ private function isForceArray(FuncCall $funcCall, Scope $scope): bool } $secondArgType = $scope->getType($args[1]->value); - $secondArgValue = $secondArgType instanceof ConstantScalarType ? $secondArgType->getValue() : null; + $secondArgValue = count($secondArgType->getConstantScalarValues()) === 1 ? $secondArgType->getConstantScalarValues()[0] : null; if (is_bool($secondArgValue)) { return $secondArgValue; diff --git a/tests/PHPStan/Analyser/nsrt/json-decode/narrow_type.php b/tests/PHPStan/Analyser/nsrt/json-decode/narrow_type.php index b00f971b56..a60f292a9f 100644 --- a/tests/PHPStan/Analyser/nsrt/json-decode/narrow_type.php +++ b/tests/PHPStan/Analyser/nsrt/json-decode/narrow_type.php @@ -32,3 +32,12 @@ function ($mixed) { $value = json_decode($mixed, false); assertType('mixed', $value); }; + +function(string $json): void { + /** @var '{}'|'null' $json */ + $value = json_decode($json); + assertType('stdClass|null', $value); + + $value = json_decode($json, true); + assertType('array{}|null', $value); +};