Передача именованных параметров в php-функцию через call_user_func_array

При попытке вызвать функцию в дочернем классе с произвольным набором параметров у меня возникает следующая проблема:

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? И да, конечно, я мог бы просто передать весь массив и справиться с ним в функции … но это не то, что я хочу сделать.

благодаря

Нет. PHP не поддерживает именованные параметры. Учитывается только порядок параметров. Вы могли бы, вероятно, взять код отдельно, используя ReflectionClass, чтобы проверить имена параметров функции, но в конце вам нужно будет использовать это, чтобы изменить порядок массива.

Фондовый 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 в соответствии с именами параметров.

Хорошие новости, у меня была такая же забота (я искал именованные аргументы в 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, )); 

Повеселись

Вы можете просто передать массив и извлечь:

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

Это будет извлекаться в качестве ссылок, поэтому почти нет накладных расходов.

Я использую битовую маску вместо логических параметров:

 // 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 

Есть способ сделать это и использовать массивы (самый простой способ):

 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/

Для тех, кто все еще может споткнуться о вопросе (как и я), вот мой подход:

начиная с PHP 5.6 вы можете использовать как упоминалось здесь :

В этом случае вы можете использовать что-то вроде этого:

 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