【问题标题】:Passing named parameters to a php function through call_user_func_array通过 call_user_func_array 将命名参数传递给 php 函数
【发布时间】:2011-07-07 12:25:52
【问题描述】:

当尝试使用任意一组参数调用子类中的函数时,我遇到了以下问题:

class Base{

    function callDerived($method,$params){
        call_user_func_array(array($this,$method),$params);
    }
}

class Derived extends Base{
    function test($foo,$bar){
        print "foo=$foo, bar=$bar\n";
    }
}

$d = new Derived();
$d->callDerived('test',array('bar'=>'2','foo'=>1));

输出:

foo=2, bar=1

这...不是我想要的——有没有办法实现这个超越用func_get_args的索引顺序重新组合数组?是的,当然,我可以简单地传递整个数组并在函数中处理它......但这不是我想要做的。

谢谢

【问题讨论】:

  • 我觉得你在这里运气不好......
  • 没办法。此外,您不知道自己方法的参数顺序也让人感到不舒服:X 如果您想确保特定顺序,也许您应该考虑使用interfaces。跨度>
  • @KingCrunch 实际上,我不确定的是我得到的参数数组的顺序 - 但是是的,这是一个笨拙的情况。
  • @Wagemage:也许你只是不需要call_user_func_array()call_user_func('func', $array['foo'], $array['bar']);
  • @KingCrunch 是的,我明白你的意思了——但是对于不同的派生类,调用将有不同数量和参数的顺序......这是我试图消除悲观情绪的一个问题,不是我正在尝试编写的全新代码。

标签: php function


【解决方案1】:

没有。 PHP 不支持命名参数。只考虑参数的顺序。您可能可以使用 ReflectionClass 将代码本身拆开来检查函数参数名称,但最终您还是需要使用它来重新排序数组。

【讨论】:

  • 是的,我很害怕。哦,好吧...该死的美学,我可以通过 func_get_args 的东西来处理它。
  • 现在在PHP 8 中支持命名参数:)
【解决方案2】:

普通的 PHP 类 ReflectionMethod 是你的朋友。

例子:

class MyClass { 
    function myFunc($param1, $param2, $param3='myDefault') { 
        print "test"; 
    } 
}

$refm = new ReflectionMethod('MyClass', 'myFunc');

foreach ($refm->getParameters() as $p) 
    print "$p\n";

结果:

Parameter #0 [ <required> $param1 ]
Parameter #1 [ <required> $param2 ]
Parameter #2 [ <optional> $param3 = 'myDefault' ]

此时你知道了目标函数的参数名称。有了这些信息,您可以修改您的方法'callDerived',并且可以根据参数名称将数组重新排序为call_user_func_array

【讨论】:

    【解决方案3】:

    好消息,我也有同样的担忧(我一直在寻找 PHP 中的命名参数,就像 Python 一样),并找到了这个有用的工具:https://github.com/PHP-DI/Invoker

    这使用反射 API 为可调用对象提供数组中的一些参数,并为数组中未定义的其他参数使用可选参数默认值。

    $invoker = new Invoker\Invoker;
    $result = $invoker->call(array($object, 'method'), array(
        "strName"  => "Lorem",
        "strValue" => "ipsum",
        "readOnly" => true,
        "size"     => 55,
    ));
    

    玩得开心

    【讨论】:

    • DownVote:那不叫“命名参数”。那只是将映射传递给函数。命名参数将支持代码完成、反射、...
    【解决方案4】:

    您可以简单地传递一个数组并提取:

    function add($arr){
        extract($arr, EXTR_REFS);
        return $one+$two;
    }
    $one = 1;
    $two = 2;
    echo add(compact('one', 'two')); // 3
    

    这将提取为引用,因此几乎没有开销。

    【讨论】:

      【解决方案5】:

      我使用位掩码而不是布尔参数:

      // Ingredients
      define ('TOMATO',    0b0000001);
      define ('CHEESE',    0b0000010);
      define ('OREGANO',   0b0000100);
      define ('MUSHROOMS', 0b0001000);
      define ('SALAMI',    0b0010000);
      define ('PEPERONI',  0b0100000);
      define ('ONIONS',    0b1000000);
      
      function pizza ($ingredients) {
        $serving = 'Pizza with';
        $serving .= ($ingredients&TOMATO)?' Tomato':''; 
        $serving .= ($ingredients&CHEESE)?' Cheese':''; 
        $serving .= ($ingredients&OREGANO)?' Oregano':''; 
        $serving .= ($ingredients&MUSHROOMS)?' Mushrooms':''; 
        $serving .= ($ingredients&SALAMI)?' Salami':''; 
        $serving .= ($ingredients&ONIONS)?' Onions':''; 
        return trim($serving)."\n" ;
      }
      
      // Now order your pizzas!
      echo pizza(TOMATO | CHEESE | SALAMI); 
      echo pizza(ONIONS | TOMATO | MUSHROOMS | CHEESE); // "Params" are not positional
      

      【讨论】:

        【解决方案6】:

        更新:PHP 8 现在支持命名参数。如果您传递关联数组,它可以与call_user_func_array 一起使用。所以你可以简单地这样做:

        <?php
        
        function myFunc($foo, $bar) {
            echo "foo=$foo, bar=$bar\n";
        }
        
        call_user_func_array('myFunc', ['bar' => 2, 'foo' => 1]);
        // Outputs:  foo=1, bar=2
        

        在您的代码中,您会很高兴知道您不必更改任何内容。只需升级到 PHP 8,它就会按预期工作

        【讨论】:

          【解决方案7】:

          对于那些仍然可能偶然发现这个问题的人(就像我一样),这是我的方法:

          PHP 5.6 开始,您可以使用 ... 如提到的here:

          在这种情况下,您可以使用以下内容:

          class Base{
          
              function callDerived($method,...$params){
                      call_user_func_array(array($this,$method),$params);
                  }
          }
          
          class Derived extends Base{
              function test(...$params){
                  foreach ($params as $arr) {
                      extract($arr);
                  }
                  print "foo=$foo, bar=$bar\n";
              }
          }
          
          $d = new Derived();
          $d->callDerived('test',array('bar'=>'2'),array('foo'=>1)); 
          
          //print: foo=1, bar=2
          

          【讨论】:

            【解决方案8】:

            有一种方法可以做到这一点,并且是使用数组(最简单的方法):

            class Test{
                public $a  = false;
                private $b = false;
                public $c  = false;
                public $d  = false;
                public $e  = false;
                public function _factory(){
                    $args    = func_get_args();
                    $args    = $args[0];
                    $this->a = array_key_exists("a",$args) ? $args["a"] : 0;
                    $this->b = array_key_exists("b",$args) ? $args["b"] : 0;
                    $this->c = array_key_exists("c",$args) ? $args["c"] : 0;
                    $this->d = array_key_exists("d",$args) ? $args["d"] : 0;
                    $this->e = array_key_exists("e",$args) ? $args["e"] : 0;
                }
                public function show(){
                    var_dump($this);
                }
            }
            
            $test = new Test();
            $args["c"]=999;
            $test->_factory($args);
            $test->show();
            

            完整的解释可以在我的博客中找到: http://www.tbogard.com/2013/03/07/passing-named-arguments-to-a-function-in-php/

            【讨论】:

            • 严肃?希望你永远不会搞砸$this-&gt;e = array_key_exists("d",$args) ? $args["e"] : 0; 之类的东西,调试起来会非常耗时......顺便说一句,你使用 7 行代码只是为了在调用函数时保存一些参数?显然不值得。
            猜你喜欢
            • 2014-04-13
            • 2017-04-14
            • 2011-12-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-22
            • 2019-12-19
            • 2021-11-29
            相关资源
            最近更新 更多