Pasar una matriz como argumentos, no una matriz, en PHP

148

Me parece recordar que en PHP hay una manera de pasar una matriz como una lista de argumentos para una función, desreferenciando la matriz a la func($arg1, $arg2)manera estándar . Pero ahora estoy perdido en cómo hacerlo. Recuerdo la forma de pasar por referencia, cómo "englobar" los parámetros entrantes ... pero no cómo quitar la lista de la matriz en una lista de argumentos.

Puede ser tan simple como func(&$myArgs), pero estoy bastante seguro de que no lo es. Pero, lamentablemente, el manual de php.net no ha divulgado nada hasta ahora. No es que haya tenido que usar esta característica en particular durante el último año más o menos.

Robert K
fuente

Respuestas:

178

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

call_user_func_array('func',$myArgs);
vartec
fuente
1
Podría haber jurado que también era una no función, como un prefijo o algo así. Gracias.
Robert K
8
¡Pero no sé Python! Debo ser accidentalmente psíquico ...: D
Robert K
45
El desempaquetado de argumentos, como se le llama, se agregará en PHP 5.6 ( wiki.php.net/rfc/argument_unpacking ). Utilizará el 'operador de splat': '...'. Su sintaxis: $args = [1,2,3]; function(...$args){}
arothuis
44
pero, ¿qué sucede si la función que desea llamar es un método de instancia en un objeto, no un nombre de función en el espacio global?
ahnbizcad
66
@ahnbizcad, entonces debe usar a callable, que usa lo mismo call_user_func_array, solo con una matriz donde el primer elemento es el objeto y el segundo es el método. Por ejemplocall_user_func_array([$object, 'method'], $myArgs);
SteveB el
149

Como se ha mencionado , a partir de PHP 5.6+ puede (debería) usar el ...token (también conocido como "operador splat", parte de la funcionalidad de funciones variadas ) para llamar fácilmente a una función con una variedad 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: los elementos de la matriz se asignan a argumentos por su posición en la matriz, no por sus claves.

Según el comentario de CarlosCarucce , esta forma de desempaquetar argumentos es el método más rápido con diferencia en todos los casos. En algunas comparaciones, es más de 5 veces más rápido que call_user_func_array.

Aparte

Porque creo que esto es realmente útil (aunque no está directamente relacionado con la pregunta): puede insinuar el parámetro del operador splat en la definición de su función para asegurarse de que todos los valores pasados ​​coincidan con un tipo específico.

(Solo recuerde que hacer esto DEBE ser el último parámetro que defina y que agrupa todos los parámetros pasados ​​a la función en la matriz).

Esto es excelente para asegurarse de que una matriz contenga elementos de un 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
fuente
77
Esto tiene una gran mejora en el rendimiento call_user_func_array. Entonces, si está utilizando php 5.6+, recomendaría este. Aquí hay una prueba , que fue citada en el wiki oficial de php
CarlosCarucce
2
Es realmente lamentable que esta no sea la respuesta marcada. Definitivamente mucho mejor
inolvidable1987
81

También tenga en cuenta que si desea aplicar un método de instancia a una matriz, debe pasar la función como:

call_user_func_array(array($instance, "MethodName"), $myArgs);
Jeff Ober
fuente
44
@understack El $foo->bar()ejemplo en la página vinculada sugiere que debería serlo array($instance, "MethodName").
Paul Calcraft
11
Impresionante, usé esto para evitar duplicar argumentos de constructor en una clase secundaria :)call_user_func_array(array(parent, "__construct"), func_get_args());
Jason
10

En aras de la integridad, a partir de PHP 5.1 esto también 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"
?>

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

Para los métodos, utilice ReflectionMethod :: invokeArgs en su lugar y pase el objeto como primer parámetro.

DanMan
fuente
¡Esto es realmente lo que he estado buscando!
Dij