diff --git a/src/Type/Php/ArrayFirstLastDynamicReturnTypeExtension.php b/src/Type/Php/ArrayFirstLastDynamicReturnTypeExtension.php index 18a7d547ec..859f36f1f0 100644 --- a/src/Type/Php/ArrayFirstLastDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayFirstLastDynamicReturnTypeExtension.php @@ -6,6 +6,7 @@ use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Reflection\FunctionReflection; +use PHPStan\ShouldNotHappenException; use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\NullType; use PHPStan\Type\Type; @@ -19,7 +20,12 @@ final class ArrayFirstLastDynamicReturnTypeExtension implements DynamicFunctionR public function isFunctionSupported(FunctionReflection $functionReflection): bool { - return in_array($functionReflection->getName(), ['array_first', 'array_last'], true); + return in_array($functionReflection->getName(), [ + 'array_key_first', + 'array_key_last', + 'array_first', + 'array_last', + ], true); } public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type @@ -37,13 +43,24 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return new NullType(); } - $valueType = $argType->getIterableValueType(); + switch ($functionReflection->getName()) { + case 'array_key_first': + case 'array_key_last': + $resultType = $argType->getIterableKeyType(); + break; + case 'array_first': + case 'array_last': + $resultType = $argType->getIterableValueType(); + break; + default: + throw new ShouldNotHappenException(); + } if ($iterableAtLeastOnce->yes()) { - return $valueType; + return $resultType; } - return TypeCombinator::union($valueType, new NullType()); + return TypeCombinator::union($resultType, new NullType()); } } diff --git a/src/Type/Php/ArrayKeyFirstDynamicReturnTypeExtension.php b/src/Type/Php/ArrayKeyFirstDynamicReturnTypeExtension.php deleted file mode 100644 index 2e926f7554..0000000000 --- a/src/Type/Php/ArrayKeyFirstDynamicReturnTypeExtension.php +++ /dev/null @@ -1,43 +0,0 @@ -getName() === 'array_key_first'; - } - - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type - { - if (!isset($functionCall->getArgs()[0])) { - return null; - } - - $argType = $scope->getType($functionCall->getArgs()[0]->value); - $iterableAtLeastOnce = $argType->isIterableAtLeastOnce(); - if ($iterableAtLeastOnce->no()) { - return new NullType(); - } - - $keyType = $argType->getIterableKeyType(); - if ($iterableAtLeastOnce->yes()) { - return $keyType; - } - - return TypeCombinator::union($keyType, new NullType()); - } - -} diff --git a/src/Type/Php/ArrayKeyLastDynamicReturnTypeExtension.php b/src/Type/Php/ArrayKeyLastDynamicReturnTypeExtension.php deleted file mode 100644 index a750c9bea5..0000000000 --- a/src/Type/Php/ArrayKeyLastDynamicReturnTypeExtension.php +++ /dev/null @@ -1,43 +0,0 @@ -getName() === 'array_key_last'; - } - - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type - { - if (!isset($functionCall->getArgs()[0])) { - return null; - } - - $argType = $scope->getType($functionCall->getArgs()[0]->value); - $iterableAtLeastOnce = $argType->isIterableAtLeastOnce(); - if ($iterableAtLeastOnce->no()) { - return new NullType(); - } - - $keyType = $argType->getIterableKeyType(); - if ($iterableAtLeastOnce->yes()) { - return $keyType; - } - - return TypeCombinator::union($keyType, new NullType()); - } - -}