Cómo pasar un número variable de argumentos a una función PHP

115

Tengo una función PHP que toma un número variable de argumentos (usando func_num_args()y func_get_args()), pero el número de argumentos que quiero pasar a la función depende de la longitud de una matriz. ¿Hay alguna forma de llamar a una función PHP con un número variable de argumentos?

Sin sombrero
fuente
1
Verifique mi respuesta para obtener información sobre un operador de splat en el nuevo php5.6: stackoverflow.com/a/23163963/1090562
Salvador Dali

Respuestas:

132

Si tiene sus argumentos en una matriz, es posible que le interese la call_user_func_arrayfunción.

Si la cantidad de argumentos que desea pasar depende de la longitud de una matriz, probablemente signifique que puede empaquetarlos en una matriz ellos mismos, y usar ese para el segundo parámetro de call_user_func_array.

Los elementos de esa matriz que pase serán recibidos por su función como parámetros distintos.


Por ejemplo, si tiene esta función:

function test() {
  var_dump(func_num_args());
  var_dump(func_get_args());
}

Puede empaquetar sus parámetros en una matriz, como esta:

$params = array(
  10,
  'glop',
  'test',
);

Y, luego, llame a la función:

call_user_func_array('test', $params);

Este código será el resultado:

int 3

array
  0 => int 10
  1 => string 'glop' (length=4)
  2 => string 'test' (length=4)

es decir, 3 parámetros; exactamente como iof la función se llamó de esta manera:

test(10, 'glop', 'test');
Pascal MARTIN
fuente
1
Si, gracias. call_user_func_array () es exactamente la función que estaba buscando.
nohat
¿Es posible usar call_user_func_array () con una llamada al método de objeto?
nohat
6
@nohat: de nada :-) ;; sobre el uso de un método de un objeto: sí, puedes, usando algo como array ($ obj, 'methodName') como primer parámetro ;; en realidad, puede pasar cualquier "devolución de llamada" que desee a esa función. Para obtener más información sobre las devoluciones de llamada, consulte php.net/callback#language.types.callback
Pascal MARTIN
58

Esto ahora es posible con PHP 5.6.x , usando el operador ... (también conocido como operador splat en algunos idiomas):

Ejemplo:

function addDateIntervalsToDateTime( DateTime $dt, DateInterval ...$intervals )
{
    foreach ( $intervals as $interval ) {
        $dt->add( $interval );
    }
    return $dt;
}

addDateIntervaslToDateTime( new DateTime, new DateInterval( 'P1D' ), 
        new DateInterval( 'P4D' ), new DateInterval( 'P10D' ) );
JCM
fuente
1
La lista de argumentos de variables escritas es una característica introducida en PHP 7 .
Daniele Orlando
46

En un nuevo Php 5.6 , puede usar en ... operatorlugar de usar func_get_args().

Entonces, usando esto, puede obtener todos los parámetros que pasa:

function manyVars(...$params) {
   var_dump($params);
}
Salvador Dalí
fuente
3
Más información aquí: php.net/manual/en/…
fracz
Desde el enlace @fracz, OP está intentando crear una "función variada".
Nathan Arthur
40

Desde PHP 5.6 , se puede especificar una lista de argumentos variables con el ...operador.

function do_something($first, ...$all_the_others)
{
    var_dump($first);
    var_dump($all_the_others);
}

do_something('this goes in first', 2, 3, 4, 5);

#> string(18) "this goes in first"
#>
#> array(4) {
#>   [0]=>
#>   int(2)
#>   [1]=>
#>   int(3)
#>   [2]=>
#>   int(4)
#>   [3]=>
#>   int(5)
#> }

Como puede ver, el ...operador recopila la lista variable de argumentos en una matriz.

Si necesita pasar los argumentos de la variable a otra función, ...aún puede ayudarlo.

function do_something($first, ...$all_the_others)
{
    do_something_else($first, ...$all_the_others);
    // Which is translated to:
    // do_something_else('this goes in first', 2, 3, 4, 5);
}

Desde PHP 7 , la lista de variables de argumentos puede ser obligado a ser todos del mismo tipo también.

function do_something($first, int ...$all_the_others) { /**/ }
Daniele Orlando
fuente
11

Para aquellos que buscan una forma de hacer esto con $object->method:

call_user_func_array(array($object, 'method_name'), $array);

Tuve éxito con esto en una función de construcción que llama a una variable nombre_método con parámetros variables.

danilo
fuente
2
También puede utilizar$object->method_name(...$array);
Yoann Kergall
Yendo más allá, si desea pasar por referencia, use$object->method_name(&...$args);
Fabien Haddadi
4

Puedes simplemente llamarlo.

function test(){        
     print_r(func_get_args());
}

test("blah");
test("blah","blah");

Salida:

Matriz ([0] => bla) Matriz ([0] => bla [1] => bla)

Donnie C
fuente
Si entiendo el OP correctamente, el problema no es recibir los parámetros, sino llamar a la función con un número variable de parámetros.
Pascal MARTIN
1
Entonces no entendí el OP correctamente. Entonces, una matriz definitivamente sería el camino a seguir. Por otra parte, podría pasar la matriz directamente a test (), ¿no?
Donnie C
1
Pasar una matriz también podría ser una solución, de hecho, si entendí correctamente ^^
Pascal MARTIN
1
Pregunta antigua, pero para su información, una matriz funciona bien, pero pasar argumentos reales le permite usar los valores predeterminados de PHP para argumentos nulos, lo que ahorra muchas verificaciones desagradables para ver si la matriz contiene valores particulares.
Endophage
1

Una vieja pregunta, lo sé, sin embargo, ninguna de las respuestas aquí realmente hace un buen trabajo simplemente para responder la pregunta.

Acabo de jugar con php y la solución se ve así:

function myFunction($requiredArgument, $optionalArgument = "default"){
   echo $requiredArgument . $optionalArgument;
}

Esta función puede hacer dos cosas:

Si se llama solo con el parámetro requerido: myFunction("Hi") imprimirá "Hola predeterminado"

Pero si se llama con el parámetro opcional: myFunction("Hi","me") imprimirá "Hola";

Espero que esto ayude a cualquiera que esté buscando esto en el futuro.

Alex
fuente
2
No entendiste la pregunta. OP estaba preguntando sobre argumentos que no tenía que definir explícitamente en la firma de la función ; sin embargo, aún puede pasar valores como argumentos a la función. Por ejemplo, la firma de la función no tiene ningún argumento definido (opcional o no), pero cuando lo requiere, OP puede enviar 45 valores diferentes como argumentos a la función.
a20
0

Aquí hay una solución usando el método mágico __invoke

(Disponible desde php 5.3)

class Foo {
    public function __invoke($method=null, $args=[]){
        if($method){
            return call_user_func_array([$this, $method], $args);
        }
        return false;
    }

    public function methodName($arg1, $arg2, $arg3){

    }
}

Desde dentro de la misma clase:

$this('methodName', ['arg1', 'arg2', 'arg3']);

Desde una instancia de un objeto:

$obj = new Foo;
$obj('methodName', ['arg1', 'arg2', 'arg3'])
Dieter Gribnitz
fuente
Básicamente, se usa call_user_func_arraycomo se indica en la respuesta más votada en 2009. Tal vez tenga sentido envolverlo con un extra __invoke, pero no lo veo.
a20