Fix phpstan/phpstan#14397: FILTER_FLAG_GLOBAL_RANGE constant not "known" on PHP 8.3, 8.4#5334
Conversation
|
Oh I see now, PHP 8.5 has introduced And JetBrains stubs list them with the same value Thanks for the fix! :-) |
… PHP 8.3/8.4 - FILTER_FLAG_GLOBAL_RANGE (268435456) has the same numeric value as FILTER_THROW_ON_FAILURE on PHP 8.3/8.4 - This caused PHPStan to incorrectly think filter_var would throw, removing false from the return type - Gate all FILTER_THROW_ON_FAILURE checks behind PHP >= 8.5 (where the constant was introduced) - Applied fix to FilterFunctionReturnTypeHelper, FilterVarThrowTypeExtension, and FilterVarRule - Updated FilterVarRuleTest to pass new PhpVersion constructor parameter - New regression test in tests/PHPStan/Analyser/nsrt/bug-14397.php
5a53072 to
fa75094
Compare
VincentLanglet
left a comment
There was a problem hiding this comment.
Replace the check
$this->phpVersion->getVersionId() >= 80500
by a dedicated method inside phpVersion.
hasFilterThrowOnFailureConstant()
…stant() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Done. Added |
- Add nsrt test verifying filter_var with FILTER_THROW_ON_FAILURE still returns false on PHP < 8.5 (throw type extension correctly inactive) - Add FilterVarRule test verifying no error for FILTER_NULL_ON_FAILURE + FILTER_THROW_ON_FAILURE combination on PHP < 8.5 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| @@ -0,0 +1,14 @@ | |||
| <?php // lint < 8.5 | |||
|
|
|||
| namespace FilterVarNullAndThrowPrePhp85; | |||
There was a problem hiding this comment.
should we test this file on 8.5+ and pre-8.5?
There was a problem hiding this comment.
Done. Added a test (testRuleGlobalRangePhp85) that verifies FILTER_FLAG_GLOBAL_RANGE|FILTER_NULL_ON_FAILURE produces no false positive on PHP 8.5+, complementing the existing pre-8.5 test. All tests (11701) and static analysis pass. Changes pushed.
Ensures FILTER_FLAG_GLOBAL_RANGE|FILTER_NULL_ON_FAILURE does not falsely trigger the "cannot use both" error on PHP 8.5+ where the constants have distinct values. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| return []; | ||
| } | ||
|
|
||
| if (count($args) < 3) { |
There was a problem hiding this comment.
I think we should count args right after if (!($node->name instanceof Node\Name)) { to exit early with a cheap check
There was a problem hiding this comment.
Tests also confirmed passing. Everything's been pushed — the review comment from staabm has been addressed.
…checks in FilterVarRule Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
On PHP 8.3/8.4, using
FILTER_FLAG_GLOBAL_RANGEwithfilter_varcaused a false positive: "Strict comparison using === between non-falsy-string and false will always evaluate to false." This happened becauseFILTER_FLAG_GLOBAL_RANGE(268435456) shares the same numeric value asFILTER_THROW_ON_FAILUREon those PHP versions, causing PHPStan to incorrectly infer the function would throw instead of returning false.Changes
FILTER_THROW_ON_FAILUREchecks behind PHP >= 8.5 insrc/Type/Php/FilterFunctionReturnTypeHelper.php(two locations)src/Type/Php/FilterVarThrowTypeExtension.phpinisFunctionSupported()src/Rules/Functions/FilterVarRule.phpfor the null-on-failure + throw-on-failure conflict detectionRoot cause
The JetBrains PHP stubs define
FILTER_THROW_ON_FAILUREwith value 268435456 without any PHP version guard. On PHP 8.3/8.4,FILTER_FLAG_GLOBAL_RANGEalso has value 268435456 (changed to 536870912 in PHP 8.5 to avoid this exact collision). When PHPStan checked whetherFILTER_THROW_ON_FAILUREwas present in the flags via bitwise AND, it matchedFILTER_FLAG_GLOBAL_RANGEand incorrectly removedfalsefrom the return type, since throw-on-failure means the function throws instead of returning a failure value.Test
Added
tests/PHPStan/Analyser/nsrt/bug-14397.php— asserts thatfilter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_GLOBAL_RANGE)returnsnon-falsy-string|false(not justnon-falsy-string).Fixes phpstan/phpstan#14397