# RFC: Add preg_replace_callback_array function

- Status: Implemented (PHP 7.0)
- Authors: Wei Dai, demon@php.net
- Date: 2015-03-10
- Version: 1.0
- Original: https://wiki.php.net/rfc/preg_replace_callback_array
- Page: https://externals.io/rfc/preg_replace_callback_array
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

## Discussions on the mailing list

- [\[RFC\]\[DISCUSSION\] Add preg_replace_callback_array function](https://externals.io/message/84963.md) — started on 2015-03-16, 15 messages
- [\[RFC\]\[DISCUSSION\] Add preg_replace_callback_array function](https://externals.io/message/84966.md) — started on 2015-03-16, 1 messages
- [\[RFC\]\[DISCUSSION\] Add preg_replace_callback_array function](https://externals.io/message/84969.md) — started on 2015-03-16, 1 messages
- [To RFC or Not To RFC \[was Re:  回复： \[RFC\]\[DISCUSSION\] Add preg_replace_callback_array function\]](https://externals.io/message/85361.md) — started on 2015-03-21, 9 messages

---

## Introduction

Before 5.5.0, we can use the '/e' modifier. Here is a piece of code with 5.4.x:

[Zend/zend\_vm\_gen.php](https://wiki.php.net/_export/code/rfc/preg_replace_callback_array?codeblock=0)

```php
$code = preg_replace(
                array(
                    "/EXECUTE_DATA/m",
                    "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m",
                    "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*\)/me",
                    "/ZEND_VM_DISPATCH_TO_HELPER_EX\(\s*([A-Za-z_]*)\s*,\s*[A-Za-z_]*\s*,\s*(.*)\s*\);/me",
                ),
                array(
                    "execute_data",
                    "return \\1".($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)",
                    "'return '.helper_name('\\1',$spec,'$op1','$op2').'(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)'",
                    "'return '.helper_name('\\1',$spec,'$op1','$op2').'(\\2, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);'",
                ),   
                $code);
```

Since 5.5.0, we deprecated the /e modifier, so we have to change it to:

[Zend/zend\_vm\_gen.php](https://wiki.php.net/_export/code/rfc/preg_replace_callback_array?codeblock=1)

```php
$code = preg_replace_callback(
    array(
        "/EXECUTE_DATA/m",
	"/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m",
	"/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*\)/m",
	"/ZEND_VM_DISPATCH_TO_HELPER_EX\(\s*([A-Za-z_]*)\s*,\s*[A-Za-z_]*\s*,\s*(.*)\s*\);/m",
    ),
    function($matches) use ($spec, $prefix, $op1, $op2) {
	if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
	    return "execute_data";
        } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
	    return "return " . $matches[1] . ($spec?"_SPEC":"") . $prefix[$op1] . $prefix[$op2] . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
        } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) {
	    return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(" . $matches[2]. ", ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);";
        } else {
	    return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
        }
    }, $code);
```

## Proposal

The preg\_replace\_callback\_array function is an extension to preg\_replace\_callback. With the function, each pattern can easily have a specific callback.

This is the best way to implement when there are multiple patterns.

With preg\_replace\_callback\_array, the code is more readable, and full of logic. There is less crazy branch determination.

With the preg\_replace\_callback\_array function, the code is:

[Zend/zend\_vm\_gen.php](https://wiki.php.net/_export/code/rfc/preg_replace_callback_array?codeblock=2)

```php
$code = preg_replace_callback_array(
	array(
		"/EXECUTE_DATA/m" => function($matches) {
                        return "execute_data";
                 },
		"/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m" => function($matches) use ($spec, $prefix, $op1, $op2) {
		       return "return " . $matches[1] . ($spec?"_SPEC":"") . $prefix[$op1] . $prefix[$op2] . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
		},
		"/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*\)/m" => function($matches) use ($spec, $prefix, $op1, $op2) {
			return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
		},
		"/ZEND_VM_DISPATCH_TO_HELPER_EX\(\s*([A-Za-z_]*)\s*,\s*[A-Za-z_]*\s*,\s*(.*)\s*\);/m" => function($matches) use ($spec, $prefix, $op1, $op2) {
			return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(" . $matches[2]. ", ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);";
		},
	), $code);
```

The first parameter is an array in this function. In this parameter, Key is pattern, and value is callback. Subject will iterate and match each key. If it is matched, the callback will be called. In the meanwhile, the result will be the new subject and passed to the next match.

## Proposed PHP Version(s)

This is proposed for PHP7

## Unaffected PHP Functionality

preg\_filter(), preg\_replace(), preg\_replace\_callback() will stay the same.

## Proposed Voting Choices

Include these so readers know where you are heading and can discuss the proposed voting options.

State whether this project requires a 2/3 or 50%+1 majority (see [voting](https://externals.io/rfc/voting))

## Patches and Tests

Currently implemented on <https://github.com/php/php-src/pull/1171>
