Extraction Coverage

A tool can only judge the patterns it finds. This page lists, call by call, which of them reads the pattern of a PHP call: regex lint, with nikic/php-parser installed or with PHP’s tokenizer alone, the language server, the PHPStan extension, the Psalm plugin, and regex:lint of the Laravel package and of the Symfony bundle.

regex lint reads the same patterns with either strategy: the test suite runs every extraction case through both. The Laravel and Symfony commands run that same extractor on PHP files, configured by their own extraction keys rather than by regex.json (see the Laravel and Symfony guides), and add what only their framework holds: route constraints and validation rules, route requirements and validator constraints. The language server takes its configuration from regex.json.

Legend:

  • Yes: the pattern is read.
  • Types: the pattern is read when the tool’s type inference knows the argument as a constant string, from any file. PHPStan reads each of the constant strings an argument may be; Psalm reads an argument whose type is one literal string, so not a variable that may hold one of two.
  • No: the pattern is not read.

Native calls

Call CLI, php-parser CLI, tokenizer LSP PHPStan Psalm Laravel Symfony
preg_match() and the seven other preg_* functions Yes Yes Yes Yes Yes Yes Yes
Namespaced drop-ins, Safe\preg_match() Yes Yes Yes Yes No Yes Yes
new RegexIterator(), new RecursiveRegexIterator() Yes Yes Yes No No Yes Yes
filter_var(), filter_input() with FILTER_VALIDATE_REGEXP Yes Yes Yes No No Yes Yes
mb_ereg(), mb_split() (Oniguruma, not PCRE) No No No No No No No

Library calls

Every preset is read by default; extraction.interop (interop for PHPStan) narrows them. Psalm reads no preset.

Call CLI, php-parser CLI, tokenizer LSP PHPStan Psalm Laravel Symfony
Static methods of composer-pcre, nette-utils, spatie-regex, illuminate-support Yes Yes Yes Yes No Yes Yes
Nette’s utf8: true adds u to the pattern judged Yes Yes Yes No No Yes Yes
webmozart-assert, beberlei-assert: Assert::regex(), Assertion::regex() Yes Yes Yes Yes No Yes Yes
phpunit on $this->, self::, static::, parent:: Yes Yes Yes No No Yes Yes
phpunit on PHPUnit\Framework\Assert:: or TestCase:: Yes Yes Yes Yes No Yes Yes
phpunit functions, PHPUnit\Framework\assertMatchesRegularExpression() Yes Yes Yes No No Yes Yes
symfony-validator: new Regex(...), #[Assert\Regex(...)] Yes Yes Yes No No Yes Yes¹
A method called on an object of a library ($str->match(), u($s)->match(), Assert::that($v)->regex()) No No No No No No No

¹ The Symfony bundle also reads every Regex constraint from the validator’s metadata, YAML and XML mappings included; a constraint both sources read is reported once.

Your own helpers

Call CLI, php-parser CLI, tokenizer LSP PHPStan Psalm Laravel Symfony
A helper named in extraction.functions Yes Yes Yes No No Yes Yes
A function or a static method marked #[RegexPattern], called by its name Yes Yes Yes Yes No Yes Yes
The same static method called through self::, static:: or parent:: No No No Yes No No No
An instance method marked #[RegexPattern] ($this->m(), $obj->m()) No No No Yes No No No
#[RegexPattern] declared in vendor/ Yes Yes Yes Yes No Yes Yes

How the pattern is written

Argument CLI, php-parser CLI, tokenizer LSP PHPStan Psalm Laravel Symfony
A string literal Yes Yes Yes Yes Yes Yes Yes
A named argument, pattern: '/.../' Yes Yes Yes Yes Yes Yes Yes
A named argument after a spread, f(...$args, pattern: '/.../') Yes Yes Yes No No Yes Yes
A heredoc or a nowdoc Yes Yes No² Yes Yes Yes Yes
A concatenation at the call, '/'.self::PART.'/' Yes Yes No² Types Types Yes Yes
A constant of the same file, self::RE, Patterns::RE, RE Yes Yes Yes Types Types Yes Yes
static::RE of a class that may be extended No No No No No No No
A constant of another file No No No Types Types No No
A local variable whose every assignment that may reach the call is a literal Yes Yes Yes Types Types Yes Yes
A private or protected property of a final class, $this->re, out of a closure (protected: the class extends none) Yes Yes Yes No³ No³ Yes Yes
A ternary or a match over literals No No No Types No No No
A concatenation with preg_quote() of a text not known No No No No No⁴ No No

² A diagnostic needs one string literal to land in; regex lint reports these patterns, the editor does not show them.

³ A property’s type is its declared type, string, whatever its default.

⁴ Psalm types $matches from the rest of such a pattern, but judges no pattern it cannot read whole.

The rules regex lint follows to read a name, and where it reports a pattern read that way, are in the CLI guide. PHPStan and Psalm read what their own analysis proves, which reaches further in some cases and less far in others; they report a pattern at the call.

A later release may read more of these cases: see Backward compatibility.

Edit on GitHub