Flags for preg_replace_callback() and preg_replace_callback_array()

The preg_replace_callback() and preg_replace_callback_array() functions can be used to perform a regular expression search and replace using a callback.

Since PHP 7.4, an optional $flags argument can be passed to these functions. This argument is a bitmask and can be a combination of PREG_OFFSET_CAPTURE and PREG_UNMATCHED_AS_NULL. It is used to control the format of the matches array that is passed to the callback function.

The first three arguments for preg_replace_callback() are the regular expression pattern, the callback function that should be called for the matches, and the subject to be matched against the pattern. These three arguments are mandatory.

$subject  = 'abc';
$pattern  = '/./';
$callback = function (array $matches): string {
                var_dump($matches);

                return '';
            };

preg_replace_callback(
    $pattern,
    $callback,
    $subject
);

Executing the code shown above will print the output shown below:

array(1) {
  [0]=>
  string(1) "a"
}
array(1) {
  [0]=>
  string(1) "b"
}
array(1) {
  [0]=>
  string(1) "c"
}

When the PREG_OFFSET_CAPTURE flag is used then for every occurring match the string offset will also be returned. This changes the format of the matches array that is passed to the callback function to an array where every element is an array that contains the matched string as the element with key 0 and its string offset as the element with key 1.

The $flags argument needs to be passed as the sixth argument. In the example shown below, we pass the default of -1 for the first optional argument and $count for the second optional argument:

$subject  = 'abc';
$pattern  = '/./';
$callback = function (array $matches): string {
                var_dump($matches);

                return '';
            };

preg_replace_callback(
    $pattern,
    $callback,
    $subject,
    -1,
    $count,
    PREG_OFFSET_CAPTURE
);

Executing the code shown above will print the output shown below:

array(1) {
  [0]=>
  array(2) {
    [0]=>
    string(1) "a"
    [1]=>
    int(0)
  }
}
array(1) {
  [0]=>
  array(2) {
    [0]=>
    string(1) "b"
    [1]=>
    int(1)
  }
}
array(1) {
  [0]=>
  array(2) {
    [0]=>
    string(1) "c"
    [1]=>
    int(2)
  }
}

By default, the matches array that is passed to the callback function represents unmatched subpatterns as an empty string ('').

$subject  = 'abc';
$pattern  = '/(a)|(b)/';
$callback = function (array $matches): string {
                var_dump($matches);

                return '';
            };

preg_replace_callback(
    $pattern,
    $callback,
    $subject
);

Executing the code shown above will print the output shown below:

array(2) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "a"
}
array(3) {
  [0]=>
  string(1) "b"
  [1]=>
  string(0) ""
  [2]=>
  string(1) "b"
}

When the PREG_UNMATCHED_AS_NULL flag is passed then unmatched subpatterns will be represented as null instead of '' in the matches array that is passed to the callback function.

$subject  = 'abc';
$pattern  = '/(a)|(b)/';
$callback = function (array $matches): string {
                var_dump($matches);

                return '';
            };

preg_replace_callback(
    $pattern,
    $callback,
    $subject,
    -1,
    $count,
    PREG_UNMATCHED_AS_NULL
);

Executing the code shown above will print the output shown below:

array(3) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "a"
  [2]=>
  NULL
}
array(3) {
  [0]=>
  string(1) "b"
  [1]=>
  NULL
  [2]=>
  string(1) "b"
}

Using the PREG_OFFSET_CAPTURE and PREG_UNMATCHED_AS_NULL flags with preg_replace_callback_array() has the same effect on the format of the matches array that is passed to the callback functions.