Literal Pattern Passed To preg_replace
ID |
php.str_replace_preferred_preg_replace |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Efficiency |
Language |
Php |
Tags |
best-practice, efficiency |
Description
preg_replace() is called with a pattern that contains no regular-expression syntax, so the PCRE
engine is compiled and run to do what a plain string replacement does directly.
str_replace() (or str_ireplace() when the pattern carries the i modifier) produces the same
result several times faster, and tells the reader at a glance that nothing clever is happening.
Rationale
$text = preg_replace('/foo/', 'bar', $text);
$text = preg_replace('#section#', 'part', $text);
$text = preg_replace('/HELLO/i', 'hi', $text);
Every one of these compiles a pattern, allocates the match machinery and walks the subject with the regular-expression engine, for a substring swap. A reader also has to scan the pattern for metacharacters before concluding there are none.
Remediation
$text = str_replace('foo', 'bar', $text);
$text = str_replace('section', 'part', $text);
$text = str_ireplace('HELLO', 'hi', $text);
An escaped punctuation character in the pattern is still a literal, so preg_replace('/a\.b/', …)
becomes str_replace('a.b', …) — drop the backslash the pattern needed and the string function does
not.
The trigger is deliberately narrow, because the opposite advice is the common one. Nothing is reported unless all of the following hold:
-
the pattern is a literal whose delimiters strip cleanly;
-
every character in it is ordinary, or an escape of an ASCII punctuation character — a quantifier, anchor, character class, group or alternation keeps the call as it is;
-
the only modifier, if any, is
i; every other modifier changes how the subject is matched; -
the call has exactly the three arguments
str_replacetakes, with a single pattern and a single replacement — an array of patterns, a$limitargument andpreg_filterare all left alone; -
the replacement contains no
$or\, whichpreg_replacereads as group references and escapes whilestr_replacecopies them through.