Passando uma matriz como argumentos, não uma matriz, em PHP

148

Eu me lembro que no PHP existe uma maneira de passar uma matriz como uma lista de argumentos para uma função, desreferenciando a matriz da func($arg1, $arg2)maneira padrão . Mas agora estou perdido em como fazê-lo. Lembro-me da maneira de passar por referência, como "globar" os parâmetros recebidos ... mas não como remover a lista do array em uma lista de argumentos.

Pode ser tão simples quanto func(&$myArgs), mas tenho certeza que não é isso. Infelizmente, o manual do php.net não divulgou nada até agora. Não que eu tenha tido que usar esse recurso em particular nos últimos anos.

Robert K
fonte

Respostas:

178

http://www.php.net/manual/en/function.call-user-func-array.php

call_user_func_array('func',$myArgs);
vartec
fonte
1
Eu poderia jurar que também era uma não função, como um caractere de prefixo ou algo assim. Obrigado.
Robert K
8
Mas eu não conheço Python! Devo ser acidentalmente psíquica ...: D
Robert K
45
A descompactação de argumentos, como é chamada, será adicionada no PHP 5.6 ( wiki.php.net/rfc/argument_unpacking ). Ele usará o 'operador splat': '...'. Sua sintaxe: $args = [1,2,3]; function(...$args){}
arothuis
4
mas e se a função que você deseja chamar for um método de instância em um objeto, não um nome de função no espaço global?
ahnbizcad
6
@ahnbizcad, então você deve usar a callable, que usa o mesmo call_user_func_array, apenas com array onde o primeiro elemento é o objeto e o segundo é o método. Por exemplocall_user_func_array([$object, 'method'], $myArgs);
steveb
149

Como foi mencionado , no PHP 5.6+ você pode (deveria!) Usar o ...token (também conhecido como "operador de splat", parte da funcionalidade das funções variadas) para chamar facilmente uma função com uma matriz de argumentos:

<?php
function variadic($arg1, $arg2)
{
    // Do stuff
    echo $arg1.' '.$arg2;
}

$array = ['Hello', 'World'];

// 'Splat' the $array in the function call
variadic(...$array);

// 'Hello World'

Nota: os itens da matriz são mapeados para argumentos por sua posição na matriz, não por suas chaves.

De acordo com o comentário de CarlosCarucce , essa forma de descompactar argumentos é de longe o método mais rápido em todos os casos. Em algumas comparações, é mais de 5x mais rápido que call_user_func_array.

a parte, de lado

Porque acho que isso é realmente útil (embora não esteja diretamente relacionado à pergunta): você pode digitar o parâmetro do operador splat na definição de sua função para garantir que todos os valores passados ​​correspondam a um tipo específico.

(Lembre-se de que, fazendo isso, DEVE ser o último parâmetro definido e que agrupa todos os parâmetros passados ​​para a função na matriz.)

Isso é ótimo para garantir que uma matriz contenha itens de um tipo específico:

<?php

// Define the function...

function variadic($var, SomeClass ...$items)
{
    // $items will be an array of objects of type `SomeClass`
}

// Then you can call...

variadic('Hello', new SomeClass, new SomeClass);

// or even splat both ways

$items = [
    new SomeClass,
    new SomeClass,
];

variadic('Hello', ...$items);
simonhamp
fonte
7
Isso tem uma grande melhoria de desempenho call_user_func_array. Então, se você estiver usando o php 5.6+, eu recomendaria este. Aqui é um teste , que foi citado no wiki oficial php
CarlosCarucce
2
É realmente lamentável que essa não seja a resposta marcada. Definitivamente maneira melhor
unforgiven1987
81

Observe também que, se você deseja aplicar um método de instância a uma matriz, precisa passar a função como:

call_user_func_array(array($instance, "MethodName"), $myArgs);
Jeff Ober
fonte
4
@understack O $foo->bar()exemplo na página vinculada sugere que deveria ser array($instance, "MethodName").
Paul Calcraft 5/10
11
Impressionante, eu usei isso para evitar a duplicação de argumentos do construtor em uma classe criança :)call_user_func_array(array(parent, "__construct"), func_get_args());
Jason
10

Para completar, a partir do PHP 5.1, isso também funciona:

<?php
function title($title, $name) {
    return sprintf("%s. %s\r\n", $title, $name);
}
$function = new ReflectionFunction('title');
$myArray = array('Dr', 'Phil');
echo $function->invokeArgs($myArray);  // prints "Dr. Phil"
?>

Consulte: http://php.net/reflectionfunction.invokeargs

Para métodos, você usa o ReflectionMethod :: invokeArgs e passa o objeto como primeiro parâmetro.

DanMan
fonte
Na verdade, é isso que eu tenho procurado!
214 Dejv