From 1b9330615af699ff77888e7eaca2576453d0e1d4 Mon Sep 17 00:00:00 2001 From: Pascal CESCON - Amoifr Date: Mon, 5 Oct 2026 21:01:14 +0200 Subject: [PATCH 1/2] Allow ARRAY_FILTER_USE_VALUE as the mode of array_filter() and narrow its result Closes phpstan/phpstan#15372 --- resources/constantToFunctionParameterMap.php | 1 + .../ArrayFilterFunctionReturnTypeHelper.php | 5 +- tests/PHPStan/Analyser/nsrt/bug-15372.php | 17 +++++ .../CallToFunctionParametersRulePhp86Test.php | 64 +++++++++++++++++++ .../Rules/Functions/data/bug-15372.php | 11 ++++ .../data/call-to-function-php86.neon | 2 + 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-15372.php create mode 100644 tests/PHPStan/Rules/Functions/CallToFunctionParametersRulePhp86Test.php create mode 100644 tests/PHPStan/Rules/Functions/data/bug-15372.php create mode 100644 tests/PHPStan/Rules/Functions/data/call-to-function-php86.neon diff --git a/resources/constantToFunctionParameterMap.php b/resources/constantToFunctionParameterMap.php index 9da9627c70b..481b68f676e 100644 --- a/resources/constantToFunctionParameterMap.php +++ b/resources/constantToFunctionParameterMap.php @@ -305,6 +305,7 @@ 'constants' => [ 'ARRAY_FILTER_USE_KEY', 'ARRAY_FILTER_USE_BOTH', + 'ARRAY_FILTER_USE_VALUE', ], ], ], diff --git a/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php b/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php index b5affda6003..e9e7627eeab 100644 --- a/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php +++ b/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php @@ -323,7 +323,10 @@ private function determineMode(?Expr $flagArg, Scope $scope): ?int return null; } - if ($flagValues[0] === $this->getConstant('ARRAY_FILTER_USE_KEY')) { + // ARRAY_FILTER_USE_VALUE (PHP 8.6+) is 0, the default mode + if ($flagValues[0] === 0) { + return self::USE_ITEM; + } elseif ($flagValues[0] === $this->getConstant('ARRAY_FILTER_USE_KEY')) { return self::USE_KEY; } elseif ($flagValues[0] === $this->getConstant('ARRAY_FILTER_USE_BOTH')) { return self::USE_BOTH; diff --git a/tests/PHPStan/Analyser/nsrt/bug-15372.php b/tests/PHPStan/Analyser/nsrt/bug-15372.php new file mode 100644 index 00000000000..53a1f6d91e7 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-15372.php @@ -0,0 +1,17 @@ += 8.6 + +declare(strict_types = 1); + +namespace Bug15372; + +use function PHPStan\Testing\assertType; + +/** + * @param list $list + */ +function doFoo(array $list): void +{ + assertType('array, int>', array_filter($list, static fn ($item): bool => $item !== null, ARRAY_FILTER_USE_VALUE)); + assertType('array, int>', array_filter($list, static fn ($item): bool => $item !== null, mode: ARRAY_FILTER_USE_VALUE)); + assertType('array, int>', array_filter($list, static fn ($item): bool => $item !== null, 0)); +} diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRulePhp86Test.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRulePhp86Test.php new file mode 100644 index 00000000000..4a0b2bb9875 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRulePhp86Test.php @@ -0,0 +1,64 @@ + + */ +class CallToFunctionParametersRulePhp86Test extends RuleTestCase +{ + + protected function getRule(): Rule + { + $broker = self::createReflectionProvider(); + return new CallToFunctionParametersRule( + $broker, + new FunctionCallParametersCheck( + new RuleLevelHelper( + $broker, + checkNullables: true, + checkThisOnly: false, + checkUnionTypes: true, + checkExplicitMixed: true, + checkImplicitMixed: true, + checkBenevolentUnionTypes: false, + discoveringSymbolsTip: true, + ), + new NullsafeCheck(), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + $broker, + checkArgumentTypes: true, + checkArgumentsPassedByReference: true, + checkExtraArguments: true, + checkMissingTypehints: true, + ), + ); + } + + public function testBug15372(): void + { + $this->analyse([__DIR__ . '/data/bug-15372.php'], [ + [ + 'Constant SORT_REGULAR is not allowed for parameter #3 $mode of function array_filter.', + 10, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/data/call-to-function-php86.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Functions/data/bug-15372.php b/tests/PHPStan/Rules/Functions/data/bug-15372.php new file mode 100644 index 00000000000..ab92e51c83c --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-15372.php @@ -0,0 +1,11 @@ + $v > 1, ARRAY_FILTER_USE_VALUE); + array_filter($a, fn ($v) => $v > 1, mode: ARRAY_FILTER_USE_VALUE); + array_filter($a, fn ($k) => $k > 1, ARRAY_FILTER_USE_KEY); + array_filter($a, fn ($v, $k) => $v > $k, ARRAY_FILTER_USE_BOTH); + array_filter($a, fn ($v) => $v > 1, SORT_REGULAR); +}; diff --git a/tests/PHPStan/Rules/Functions/data/call-to-function-php86.neon b/tests/PHPStan/Rules/Functions/data/call-to-function-php86.neon new file mode 100644 index 00000000000..77372e44d42 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/call-to-function-php86.neon @@ -0,0 +1,2 @@ +parameters: + phpVersion: 80600 From 467ee835725c77623801578e7bb4ae2c2ae180ef Mon Sep 17 00:00:00 2001 From: Pascal CESCON - Amoifr Date: Mon, 5 Oct 2026 21:19:59 +0200 Subject: [PATCH 2/2] Validate the constant map against PHP 8.6 and add the missing lint comment --- tests/PHPStan/Reflection/constantToFunctionParameterMap.neon | 2 +- .../Rules/Functions/CallToFunctionParametersRulePhp86Test.php | 2 +- tests/PHPStan/Rules/Functions/data/bug-15372.php | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/PHPStan/Reflection/constantToFunctionParameterMap.neon b/tests/PHPStan/Reflection/constantToFunctionParameterMap.neon index 72ae924610a..7e44150e458 100644 --- a/tests/PHPStan/Reflection/constantToFunctionParameterMap.neon +++ b/tests/PHPStan/Reflection/constantToFunctionParameterMap.neon @@ -1,2 +1,2 @@ parameters: - phpVersion: 80500 + phpVersion: 80600 diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRulePhp86Test.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRulePhp86Test.php index 4a0b2bb9875..6111a053e4b 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRulePhp86Test.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRulePhp86Test.php @@ -49,7 +49,7 @@ public function testBug15372(): void $this->analyse([__DIR__ . '/data/bug-15372.php'], [ [ 'Constant SORT_REGULAR is not allowed for parameter #3 $mode of function array_filter.', - 10, + 12, ], ]); } diff --git a/tests/PHPStan/Rules/Functions/data/bug-15372.php b/tests/PHPStan/Rules/Functions/data/bug-15372.php index ab92e51c83c..d567a5eeb15 100644 --- a/tests/PHPStan/Rules/Functions/data/bug-15372.php +++ b/tests/PHPStan/Rules/Functions/data/bug-15372.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types = 1); namespace Bug15372;