Передача именованных параметров в функцию php через call_user_func_array - PullRequest
12 голосов
/ 07 июля 2011

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

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 ]

22 голосов
/ 07 июля 2011

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

8 голосов
/ 20 сентября 2013

Класс 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 в соответствии с именами параметров.

4 голосов
/ 25 июня 2015

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

Веселись

3 голосов
/ 04 декабря 2016

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

// 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
3 голосов
/ 02 марта 2016

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

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

Это извлечет как ссылки, так что затраты почти отсутствуют.

1 голос
/ 06 февраля 2017

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

, начиная с 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
0 голосов
/ 08 марта 2013

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

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/

...