1.2.982. Possible Missing Subpattern

When capturing subpatterns are the last ones in a regex, PHP doesn’t fill their spot in the resulting array. This leads to a possible missing index in the result array.

The same applies to preg_replace() : the pattern may match the string, but no value is available is the corresponding sub-pattern.

In PHP 7.4, a new option was added : PREG_UNMATCHED_AS_NULL, which always provides a value for the subpatterns.

<?php

// displays a partial array, from 0 to 1
preg_match('/(a)(b)?/', 'adc', $r);
print_r($r);
/*
Array
(
    [0] => a
    [1] => a
)
*/

// displays a full array, from 0 to 2
preg_match('/(a)(b)?/', 'abc', $r);
print_r($r);

/*
Array
(
    [0] => ab
    [1] => a
    [2] => b
)
*/

// double 'b' when it is found
print preg_replace(',^a(b)?,', './$1$1', 'abc'); // prints ./abbc
print preg_replace(',^a(b)?,', './$1$1', 'adc'); // prints ./dc

?>

See also Bug #73948 Preg_match_all should return NULLs on trailing optional capture groups. and Bug #50887 preg_match , last optional sub-patterns ignored when empty.

1.2.982.1. Suggestions

  • Add an always capturing subpatterns after the last ?

  • Move the ? inside the parenthesis, so the parenthesis is always on, but the content may be empty

  • Add a test on the last index of the resulting array, to ensure it is available when needed

  • Use the PREG_UNMATCHED_AS_NULL option (PHP 7.4+)

1.2.982.2. Specs

Short name

Php/MissingSubpattern

Rulesets

All, Analyze, CE, CI-checks, Changed Behavior, Top10

Exakat since

1.6.1

PHP Version

All

Severity

Minor

Time To Fix

Quick (30 mins)

Precision

Very high

Features

regex

Examples

phpMyAdmin, SPIP

Available in

Entreprise Edition, Community Edition, Exakat Cloud