rfc:second_arg_to_preg_callback

PHP RFC: Add an Second argument to callback of preg_replace_callback

Introduction

there comes a FR: https://bugs.php.net/bug.php?id=64730

the main idea basically is, in 5.5 we remove support of 'e' modifier, then comes a problem, the old codes(a real use case see https://github.com/php/php-src/blob/PHP-5.4/Zend/zend_vm_gen.php#L390):

<?php
   preg_replace(array(
 
        "/pattern1(.*)/", 
        "/pattern2(.*)/"
   ),
   array(
        "/replace1/e",
        "/replace2/e"
    )
    ..);
?>

can not be easier convert to the “callback” style.

then I have to change it to something very ugly like(a real use case see: https://github.com/php/php-src/blob/PHP-5.5/Zend/zend_vm_gen.php#L390):

<?php
   function callback($subject) {
       if (!strncmp($subject, "pattern1", 8)) { 
             //function for pattern 1
       }  else if(!strncmp($subject, "pattern2", 8)) {
            //function for pattern 2 
       } else .....  
 
   }

so I propose to add a second argument to callback(aim to php-5.5.1), which is the matched regex's index.

then we can simplify the previous codes to:

<?php
 
   function callback($matchs, $regex_key) {
       switch ($regex_key) {
          case 0:
          break;
          case 1:
          break;
       }
   }
 
   $patter = array(
        "/pattern1(.*)/", 
        "/pattern2(.*)/"
   );
 
   preg_replace($pattern, "callback", "....");
 

About Objects

Nikic said, a foreach look here is enough, like:

<?php
   $regex = array(
     "/pattern1(.*)/" => "callback1",
     "/pattern2(.*)/" => "callback2",
   );
 
   foreach ($regex as $r => $c) {
      $str = preg_repleace_callback($r, $c, $str); 
   }

for this idea, there some problems:

1. you have to define various functions for different regex

2. it's inefficient, since there need multiple function call, multiple argument processing etc.

Other Ideas

1. the reporter(#64730) suggest “I think it would be better if prey_replace_callback function will accept array of callbacks as a 2nd argument.”

but it's can not be achieved, because(by ww dot galen at gmail dot com):

“Accepting an array of callbacks can lead to unreconcilable ambiguities. For example:

  class A {
      function __toString() { ... }
      function __invoke($a) { ... }
      function foo($a) { ... }
  }
  function foo($a) { ... }
  
  $a = new A;
  preg_replace_callback([..., ...], [$a, 'foo'], $subject);
  There are three different ways of interpreting the callback argument, all equally valid:
  
   1. `(string)$a` and `foo(...)`
   2. `$a(...)` and `foo(...)`
   3. `$a->foo(...)` " 
   

2. Nikic suggest the first argument of preg_replace_callback accept array(“regex” => “callback”);

but it can not be achieved either , because, thinking of: $regex = array(“regex”); and there by accident is a function called regex, then the key “0” can be considered as a “regex” too.

Patch

rfc/second_arg_to_preg_callback.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1