preg_replace_callback_array

Applies several regex patterns, each with its own callback, to a subject in one call.

Signature
preg_replace_callback_array(array $pattern, string|array $subject, int $limit = -1, int &$count = null, int $flags = 0): string|array|null
  • Added in PHP 7.0

Parameters

ParameterTypeDescription
$patternarrayAn array whose keys are patterns and whose values are the callables to run for the matches of that pattern.
$subjectstring|arrayThe string, or array of strings, to run the replacements on.
$limitoptionalint= -1Maximum replacements per pattern per subject; -1 means unlimited.
$countoptionalint= nullPassed by reference and filled with the total number of replacements across all patterns.
$flagsoptionalint= 0PREG_OFFSET_CAPTURE and/or PREG_UNMATCHED_AS_NULL, changing the shape of the array handed to each callback.

Return value

string|array|nullAn array if subject is an array, otherwise a string. Returns null if an error occurred.

Errors

A TypeError is thrown if any value in pattern is not callable. Returns null and emits an E_WARNING if one of the keys is not a valid pattern; exceptions thrown inside a callback propagate out of the call.

Changelog

  • PHP 7.4.0The flags parameter was added.

preg_replace_callback_array() takes a map of pattern => callable and runs them all over the same subject, saving you a chain of preg_replace_callback() calls with the result of each feeding the next.

When to reach for it

It suits small rule sets applied to the same text: a mini markup converter where one pattern handles **bold**, another *italic* and a third bare URLs; a log scrubber with one rule per kind of secret; a unit converter with a rule per unit. Keeping the rules in one array also makes them easy to define elsewhere and pass in.

What trips people up

The patterns are applied in order, each over the previous one's output — not simultaneously against the original string. A rule that produces text a later rule matches will fire twice, which is exactly how ['/a/' => …'b', '/b/' => …'c'] turns aaa into ccc. Order your rules accordingly, and put the most specific first. Also remember the patterns are array keys: two identical patterns collapse into one entry, and $count is the total across every rule, not per rule.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Convert a small markup dialect (bold, italic, links) to HTML in one pass
  • Redact several classes of secret — tokens, emails, card numbers — from a log line
  • Normalise multiple date and number formats in imported text with one rule each

Frequently asked questions

Are the patterns in preg_replace_callback_array applied at the same time?

No. They are applied one after another, each on the result of the previous, so an earlier replacement can be re-matched by a later pattern. Order the array from most specific to least specific.

What is the difference from calling preg_replace_callback several times?

There is no behavioural difference — it is the same sequential application in a single call, with one shared $count. It mainly keeps a rule set together as data instead of a chain of statements.

Can I use the same pattern twice with different callbacks?

No. The patterns are array keys, so a duplicate silently overwrites the earlier entry. Combine the logic into one callback or vary the pattern.

More examples

Rules run in sequence, not in parallel

The output is 'ccc', not 'bbb'. The first rule turns every a into b, then the second rule runs on that result and turns those new b's into c. Swapping the two rules would print 'bbb'.

Example · php
<?php
echo preg_replace_callback_array([
    '/a/' => fn($m) => 'b',
    '/b/' => fn($m) => 'c',
], 'aaa'), "\n";

Counting across all rules

$count is 3 — two cats plus one dog — because it aggregates every rule. There is no per-pattern count, so if you need one, increment a counter inside each callback.

Example · php
<?php
$text = 'cat dog cat bird';

$out = preg_replace_callback_array([
    '/cat/' => fn($m) => 'CAT',
    '/dog/' => fn($m) => 'DOG',
], $text, -1, $count);

echo $out, "\n";
echo "total replacements: $count\n";

A tiny markup converter

The bold rule must come first: once ** pairs are consumed, the single-asterisk rule can only match real italics. Reversing the order would let the italic rule eat one asterisk from each ** pair and produce broken markup.

Example · php
<?php
$src = 'Read **the docs** and *try* it.';

echo preg_replace_callback_array([
    '/\*\*(.+?)\*\*/' => fn($m) => '<strong>' . $m[1] . '</strong>',
    '/\*(.+?)\*/'     => fn($m) => '<em>' . $m[1] . '</em>',
], $src), "\n";

Discussion

  • Be the first to comment on this lesson.