Conversation
zonuexe
force-pushed
the
range/throw-type
branch
from
September 22, 2026 20:03
10cdacf to
2bfc19a
Compare
This was referenced Sep 22, 2026
PHP 8.0-8.2 ignore the sign of the step and, for numeric boundaries, reject one that is 0 or wider than the range; PHP 7 does the same with a warning and false instead of a ValueError. PHP 8.3 checks a step of 0, a NAN step and a step of PHP_INT_MIN before the boundaries, rejects a negative step on an increasing range, and builds a character range from two single bytes, in which a float step turns every character but a digit into 0. RangeFunctionArgumentsHelper::rejects() answers for the PHP versions of the scope, with PhpVersions::hasStricterRangeFunction() telling them apart. It uses the verdict of calling range() only when PHPStan itself runs on PHP 8.3 or newer, and leaves undecided what it cannot tell without running an older PHP: string boundaries before PHP 8.3, and numbers beyond 2 ** 53, which PHP compares exactly as integers. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
zonuexe
force-pushed
the
range/throw-type
branch
2 times, most recently
from
September 22, 2026 21:09
eff5b7f to
8c793b0
Compare
PhpStorm stubs declare `@throws \ValueError` on range(), so every call became an explicit throw point and a catch around a valid call was never reported as dead. The extension returns void on PHP 7, which does not throw, and on PHP 8 when the native argument types are constant numbers or strings, RangeFunctionArgumentsHelper finds that no analysed PHP version rejects them, and the range has fewer items than RANGE_SIZE_LIMIT, the HT_MAX_SIZE of a 32-bit PHP. A range whose number of items does not fit into a float keeps the throw point as well. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
zonuexe
force-pushed
the
range/throw-type
branch
from
September 22, 2026 21:13
8c793b0 to
a864786
Compare
zonuexe
marked this pull request as ready for review
September 22, 2026 21:15
Collaborator
|
This pull request has been marked as ready for review. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PhpStorm stubs declare
@throws \ValueErroronrange(), so every call is an explicit throw point and PHPStan does not report a catch around a valid call as dead:On PHP 8.0+,
range()throwsValueErrorfor:0, or one wider than the range, which covers an infinite step;PHP_INT_MIN(8.3+);PHP 7 reported these with a warning and a
falsereturn value.The extension looks at native types. It returns
VoidTypeon PHP 7, and on PHP 8 when it can prove the call succeeds:RangeFunctionArgumentsHelperfinds that no analysed PHP version rejects the arguments. It checks the PHP 8.3 rules and the older ones separately. For a range of at mostARRAY_COUNT_LIMITitems it also uses the verdict of callingrange(), but only when PHPStan itself runs on PHP 8.3 or newer;RANGE_SIZE_LIMIT, theHT_MAX_SIZEof a 32-bit PHP. A range whose number of items does not fit into a float, such asrange(-1.0e308, 1.0e308), keeps the throw point.Otherwise it keeps the declared
ValueError. Two cases stay undecided on purpose:range('1', 'a', 30)is a character range on 8.3, while 8.2 turns'1'into a number and'a'into 0, and throws because 30 exceeds the range 1..0.range(0, 2 ** 60 - 1, 2 ** 60)throws on 8.2.Since the extension reads
$scope->getPhpVersion(), I split the test data byPHP_VERSION_ID. As in the sibling tests, a second method expects every catch to be dead on PHP 7, which has noValueError, and the test expectsrange('a', 'z')to be decided for PHP 8.3 only when it runs on PHP 8.3 or newer. On PHP 7 the self-analysis reports the catch inRangeFunctionArgumentsHelper::callRange()as dead, sobuild/baseline-pre-8.0.neonignores it.RangeFunctionArgumentsHelperTestcovers the cases that depend on the PHP running PHPStan. The tests fail without the extension.#6492 changes the return type of
range()and uses the same helper. I cherry-picked the helper commits into it, so the two PRs merge in either order.