Repository navigation
Conversation
yoeunes
force-pushed
the
read-regex-shapes-through-phpregex
branch
7 times, most recently
from
October 23, 2026 08:27
f29e7f3 to
affc97a
Compare
This was referenced Oct 23, 2026
yoeunes
force-pushed
the
read-regex-shapes-through-phpregex
branch
3 times, most recently
from
October 23, 2026 19:43
53cc9c4 to
c6aaf88
Compare
yoeunes
force-pushed
the
read-regex-shapes-through-phpregex
branch
3 times, most recently
from
October 24, 2026 21:29
6aff3b2 to
a54e5a6
Compare
yoeunes
force-pushed
the
read-regex-shapes-through-phpregex
branch
5 times, most recently
from
October 26, 2026 08:56
0036c0a to
6fa8c53
Compare
|
ondrej did something in phpstan#6851 |
Member
Author
Hello @staabm, thanks for the heads-up. Glad to see Hoa gone from PHPStan. I'll probably rebase this branch on the new parser and keep exploring 🙏🏻. |
yoeunes
force-pushed
the
read-regex-shapes-through-phpregex
branch
from
October 26, 2026 14:13
6fa8c53 to
3bd8185
Compare
yoeunes
force-pushed
the
read-regex-shapes-through-phpregex
branch
from
October 26, 2026 15:07
3bd8185 to
3dd2526
Compare
yoeunes
force-pushed
the
read-regex-shapes-through-phpregex
branch
6 times, most recently
from
October 26, 2026 22:53
e550d3a to
d03c755
Compare
The shapes of preg_match(), preg_match_all() and preg_replace_callback() are read from the AST and the capture shape analysis of PHPRegex, a PCRE2 pattern parser that runs on PHP 7.4. The generated parser, its grammar, its build script and the phplrt runtime are removed, and ignoreErrors patterns are validated with the same parser. Patterns are read for the analysed PHP version and the PCRE2 version it bundles; a pcreVersion parameter, or config.platform.lib-pcre in composer.json, can set that version. With bleeding edge, RegularExpressionPatternRule also reports a pattern the running PHP compiles but the analysed PHP does not. A new test matches every constant pattern of the preg_* fixtures with the engine, on generated subjects and with every flag combination, and checks that the inferred type accepts what the engine writes.
yoeunes
force-pushed
the
read-regex-shapes-through-phpregex
branch
from
October 27, 2026 04:16
d03c755 to
d80885a
Compare
|
The fixes on the PR were actually inspired by test cases in PCRE and PHP. |
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.
This is a research branch. It runs PHPStan's regex shape inference on PHPRegex, a PCRE2 pattern parser that runs on PHP 7.4, to see how the library holds up against PHPStan's tests.
What the branch does
RegexGroupParserreads the PHPRegex AST, and the type of each group comes from the library's capture shape analysis.IgnoredRegexValidatorreadsignoreErrorspatterns with the same parser.pcreVersionparameter, orconfig.platform.lib-pcrein composer.json, sets that version.RegularExpressionPatternRulealso reports a pattern the running PHP compiles but the analysed PHP does not.preg_replace_callback()callback is checked against the type its flags give, eachpreg_replace_callback_array()callback gets the shape of its own pattern, andpreg_replace()reads the group references of its replacement.How it is checked
RegexArrayShapeMatcherEngineTesttakes every constant pattern of thepreg_*fixtures, matches it with the engine on generated subjects and with every flag combination, and checks that the inferred type accepts what the engine writes. All 327 patterns pass.The full test suite passes, and
make phpstanreports no errors.poc/measures the branch and upstream2.3.xon four pattern sets (the PCRE2 and php-src test suites, patterns from open-source projects, generated edge cases), with a witness for each contradicted pattern and the scripts to replay them: seepoc/README.md.Issues this branch answers
-1for offset in mandatorypreg_match()groups when0(non-negative-int) is expected phpstan/phpstan#14959*ParameterClosureTypeExtensionfor functions which accept a array of callables phpstan/phpstan#11438preg_match()with pattern/^[a-z]+$/fails to narrow string type tonon-empty-lowercase-stringphpstan/phpstan#15018preg_match: infer digit capture groups (\d+) asdecimal-int-stringinstead ofnumeric-string, for+ intarithmetic phpstan/phpstan#14909 (where the pattern rules out a leading zero)