diff --git a/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php b/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php index 0a5f1f913e..04ef90fef5 100644 --- a/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php +++ b/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php @@ -16,6 +16,7 @@ use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\AutowiredService; +use PHPStan\Php\PhpVersion; use PHPStan\Reflection\ReflectionProvider; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; @@ -47,7 +48,10 @@ final class ArrayFilterFunctionReturnTypeHelper private const USE_KEY = 2; private const USE_ITEM = 3; - public function __construct(private ReflectionProvider $reflectionProvider) + public function __construct( + private ReflectionProvider $reflectionProvider, + private PhpVersion $phpVersion, + ) { } @@ -67,6 +71,10 @@ public function getType(Scope $scope, ?Expr $arrayArg, ?Expr $callbackArg, ?Expr } if ($arrayArgType instanceof MixedType) { + if ($this->phpVersion->throwsValueErrorForInternalFunctions()) { + return new ArrayType(new MixedType(), new MixedType()); + } + return new BenevolentUnionType([ new ArrayType(new MixedType(), new MixedType()), new NullType(), diff --git a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php index 13fd91edce..2d97663492 100644 --- a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php @@ -4854,7 +4854,7 @@ public static function dataArrayFunctions(): array 'array_filter($withPossiblyFalsey)', ], [ - '(array|null)', + PHP_VERSION_ID < 80000 ? '(array|null)' : 'array', 'array_filter($mixed)', ], [ diff --git a/tests/PHPStan/Analyser/nsrt/array-filter.php b/tests/PHPStan/Analyser/nsrt/array-filter-php7.php similarity index 96% rename from tests/PHPStan/Analyser/nsrt/array-filter.php rename to tests/PHPStan/Analyser/nsrt/array-filter-php7.php index 682e117812..e0197e9f5b 100644 --- a/tests/PHPStan/Analyser/nsrt/array-filter.php +++ b/tests/PHPStan/Analyser/nsrt/array-filter-php7.php @@ -1,6 +1,6 @@ -= 8.0 + +namespace ArrayFilterPHP8; + +use function PHPStan\Testing\assertType; + +function withoutAnyArgs(): void +{ + $filtered1 = array_filter(); + assertType('array', $filtered1); +} + +/** + * @param mixed $var1 + */ +function withMixedInsteadOfArray($var1): void +{ + $filtered1 = array_filter($var1); + assertType('array', $filtered1); +} + +/** + * @param array $map1 + * @param array $map2 + * @param array $map3 + */ +function withoutCallback(array $map1, array $map2, array $map3): void +{ + $filtered1 = array_filter($map1); + assertType('array|int<1, max>|non-falsy-string|true>', $filtered1); + + $filtered2 = array_filter($map2, null, ARRAY_FILTER_USE_KEY); + assertType('array|int<1, max>|non-falsy-string|true>', $filtered2); + + $filtered3 = array_filter($map3, null, ARRAY_FILTER_USE_BOTH); + assertType('array|int<1, max>|non-falsy-string|true>', $filtered3); +} + +function invalidCallableName(array $arr) { + assertType('*ERROR*', array_filter($arr, '')); + assertType('*ERROR*', array_filter($arr, '\\')); +}