通过call_user_func_array将命名参数传递给php函数

时间:2011-07-07 12:25:52

标签: php function

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

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的索引顺序重新组合数组?是的,当然,我可以简单地传递整个数组并在函数中处理它...但这不是我想要做的。

由于

7 个答案:

答案 0 :(得分:22)

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

答案 1 :(得分:7)

股票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

答案 2 :(得分:5)

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

这使用反射API从一个数组中提供带有一些参数的可调用对象,并且对于数组中未定义的其他参数也使用可选参数defaults。

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

玩得开心

答案 3 :(得分:3)

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

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

这将作为参考提取,因此几乎没有开销。

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

更新: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,它就会按您的预期工作

答案 6 :(得分:0)

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

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/