Las nuevas funciones variádicas de PHP 5.6

10 de octubre de 2013

PHP 5.6 no se publicará hasta dentro de varios meses, pero ya conocemos algunas de sus nuevas características. De entre todas ellas, destaca la nueva sintaxis para las "funciones variádicas".

Una función variádica es aquella que admite un número variable de argumentos. El ejemplo más conocido de estas funciones es sprintf() que formatea una cadena de texto utilizando un número indeterminado de argumentos:

// función sprintf() con 2 argumentos
echo sprintf(
    "La propiedad '%s' no existe.",
    $propiedad
);

// función sprintf() con 3 argumentos
echo sprintf(
    "La propiedad '%s' no existe para el objeto '%s'.",
    $propiedad, $objeto
);

// función sprintf() con 4 argumentos
echo sprintf(
    "La propiedad '%s' no existe para el objeto '%s' del archivo '%s'.",
    $propiedad, $objeto, $archivo
);

Este tipo de funciones se han podido crear con PHP desde hace más de diez años gracias a las variables especiales $argv y $argc y con las funciones func_get_args(), func_get_arg() y func_num_args().

La novedad es que a partir de PHP 5.6, resultará mucho más fácil crear este tipo de funciones y el código resultante será mucho más legible. Imagina que tu aplicación requiere de una función llamada media() que calcula la media de todos los números que se le pasan como argumento:

media(1, 2);                 // resultado: 1.5
media(1, 2, 7, 15);          // resultado: 6.25
media(1, 1, 2, 3, 5, 8, 13); // resultado: 4.71

Hasta la versión PHP 5.5, el código de esta función sería algo similar a lo siguiente:

function media()
{
    $numeros = func_get_args();

    return array_sum($numeros) / func_num_args();
}

A partir de PHP 5.6, cuando una función admite un número indeterminado de argumentos, se puede indicar explícitamente añadiendo tres puntos (...) por delante del nombre de una variable:

function media(...$numeros)
{
    return array_sum($numeros) / count($numeros);
}

El argumento variádico indicado con los tres puntos (...) se transforma en un array que contiene todos los argumentos pasados:

Llamada a la función Contenido de la variable $numeros
media(1) array(1)
media(1, 2) array(1, 2)
media(1, 2, 3) array(1, 2, 3)

Las funciones de PHP pueden mezclar los argumentos normales con el argumento variádico, como en el siguiente caso en el que la función media() establece un valor máximo mediante su primer argumento:

function media($valorMaximo, ...$numeros)
{
    $media = array_sum($numeros) / count($numeros);

    return min($media, $valorMaximo);
}

En este caso, si se pasan menos de dos argumentos a la función media(), el argumento variádico será un array vacío:

Llamada a la función Contenido de la variable $numeros
media(1) array()
media(1, 2) array(2)
media(1, 2, 3) array(2, 3)

Las principales restricciones de esta nueva sintaxis es que cada función solamente puede contener un argumento variádico, siempre debe ser el último argumento de la función y no puede definir un valor por defecto. Así que todas estas definiciones de funciones son incorrectas:

// ERROR: el argumento variádico debe ser el último
miFuncion(...$argumentos, $argumento1);

// ERROR: la función tiene dos argumentos variádicos
miFuncion(...$argumentos1, ...$argumentos2);

// ERROR: el argumento variádico no puede tener un valor por defecto
miFuncion($argumento1, ...$argumentos = array());

Los nuevos argumentos variádicos también soportan el type-hinting de PHP, que consiste en indicar por delante del argumento su tipo (así, si alguno de los argumentos de la función no es de ese tipo, PHP muestra un error):

miFuncion(array ...$argumentos);
miFuncion(\Symfony\Component\HttpFoundation\Request ...$peticiones);

La segunda función del ejemplo anterior obliga a que todos sus argumentos sean una instancia de la clase Request de Symfony. Si alguno de los argumentos no es de ese tipo, PHP genera un error. La ventaja de la nueva sintaxis es que esta comprobación es automática, así que no tienes que hacer un bucle que recorra todos los argumentos de la función.

Recursos útiles

La nueva sintaxis para las funciones variádicas ha sido propuesta y desarrollada por el jovencísimo programador Nikita Popov. A continuación se enlazan algunos recursos útiles para conocer en detalle cómo se incorporó la nueva sintaxis en PHP 5.6: