Skip to content

Check preg_quote delimiters in array patterns - #6474

Open
arpitjain099 wants to merge 1 commit into
phpstan:2.3.xfrom
arpitjain099:fix/preg-quote-array-patterns
Open

arpitjain099 wants to merge 1 commit into
phpstan:2.3.xfrom
arpitjain099:fix/preg-quote-array-patterns

Conversation

@arpitjain099

@arpitjain099 arpitjain099 commented Sep 18, 2026

Copy link
Copy Markdown

RegularExpressionQuotingRule bails unless the first argument is a Concat, so it only ever sees a single-string pattern. But preg_replace, preg_replace_callback and preg_filter also take an array of patterns, and those calls reach the gate and get dropped.

RegularExpressionPatternRule::extractPatterns() already reads getConstantArrays() for exactly those three functions, so the two regexp rules disagreed about what a pattern argument can be.

I added four array cases to data/preg-quote.php, each the same delimiter mismatch the rule already reports for a bare string. The test passes unchanged on 2.3.x with all four present. A fifth case whose delimiter matches stays quiet, so the branch discriminates rather than firing on every array.

One thing to decide: this adds a level 5 error to code that is currently clean. If you would rather it land behind bleeding edge first, say so and I will move it.

Regexp tests 9/9, make lint clean, phpcs clean on the touched files.

RegularExpressionQuotingRule bails unless the first argument is a Concat, so it
only ever looks at a single-string pattern. preg_replace, preg_replace_callback
and preg_filter also accept an array of patterns, which is a documented calling
convention, and each element is a pattern in its own right.

RegularExpressionPatternRule::extractPatterns() already reads that form for the
same three functions, so the two regexp rules disagreed on what a pattern
argument can look like.

Walk the array items and validate each Concat element the same way a single
pattern is validated. Other functions in the list take a single pattern, so the
array branch is limited to the three that accept one.

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
Comment on lines +97 to +115
$errors = [];
foreach ($patternArg->items as $item) {
if (!$item->value instanceof Concat) {
continue;
}

$itemDelimiters = $this->regexExpressionHelper->getPatternDelimiters($item->value, $scope);
$errors = array_merge($errors, $this->validateQuoteDelimiters($item->value, $scope, $itemDelimiters));
}

return $errors;
}

if (!$patternArg instanceof Concat) {
return [];
}

$patternDelimiters = $this->regexExpressionHelper->getPatternDelimiters($normalizedArgs[0]->value, $scope);
return $this->validateQuoteDelimiters($normalizedArgs[0]->value, $scope, $patternDelimiters);
$patternDelimiters = $this->regexExpressionHelper->getPatternDelimiters($patternArg, $scope);
return $this->validateQuoteDelimiters($patternArg, $scope, $patternDelimiters);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be de-duplicated by collecting all concats in a array first and then do the processing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants