¿PHP permite parámetros con nombre para que se puedan omitir argumentos opcionales en las llamadas a funciones?

Resuelto Stefano Borini asked hace 54 años • 16 respuestas

¿Es posible en PHP especificar un parámetro opcional con nombre al llamar a una función/método, omitiendo los que no desea especificar (como en Python)?

Algo como:

function foo($a, $b = '', $c = '') {
    // whatever
}


foo("hello", $c="bar"); // we want $b as the default, but specify $c
Stefano Borini avatar Jan 01 '70 08:01 Stefano Borini
Aceptado

PHP 8.0 agregó soporte para argumentos con nombre con la aceptación de un RFC .

Los argumentos con nombre se pasan anteponiendo al valor el nombre del parámetro seguido de dos puntos. Se permite el uso de palabras clave reservadas como nombres de parámetros. El nombre del parámetro debe ser un identificador; no se permite especificarlo dinámicamente.

Por ejemplo, para pasar solo el tercer parámetro opcional en su ejemplo:

foo(timeout: 3);

Antes de PHP 8, los parámetros con nombre no eran posibles en PHP. Técnicamente, cuando lo llamas, foo($timeout=3) se evalúa $timeout=3primero, con un resultado de 3y pasándolo como primer parámetro a foo(). Y PHP impone el orden de los parámetros, por lo que la llamada comparable debería ser foo("", "", $timeout=3). Tienes otras dos opciones:

  • Haga que su función tome una matriz como parámetro y verifique las claves de la matriz. Personalmente, esto me parece feo, pero funciona y es legible. La ventaja es la simplicidad y es fácil agregar nuevos parámetros más adelante. La desventaja es que su función se autodocumenta menos y no recibirá mucha ayuda de los IDE (autocompletar, búsquedas rápidas de parámetros de funciones, etc.).
  • Configure la función sin parámetros y solicite a PHP los argumentos usando func_get_args()o use la ... función de argumentos de longitud variable en PHP 5.6+. En función del número de parámetros, podrá decidir cómo tratar cada uno de ellos. Muchas funciones de JQuery hacen algo como esto. Esto es fácil pero puede resultar confuso para quienes llaman a sus funciones porque tampoco se autodocumenta. Y tus argumentos aún no tienen nombre.
Matt S avatar Oct 01 '2013 22:10 Matt S

No, no es posible ( antes de PHP 8.0 ): si quieres pasar el tercer parámetro, debes pasar el segundo. Y los parámetros con nombre tampoco son posibles.


Una "solución" sería usar solo un parámetro, una matriz, y pasarlo siempre... Pero no siempre definas todo lo que contiene.

Por ejemplo :

function foo($params) {
    var_dump($params);
}

Y llamándolo de esta manera: (matriz clave/valor)

foo([
    'a' => 'hello',
]);

foo([
    'a' => 'hello',
    'c' => 'glop',
]);

foo([
    'a' => 'hello',
    'test' => 'another one',
]);

Obtendrá este resultado:

array
  'a' => string 'hello' (length=5)

array
  'a' => string 'hello' (length=5)
  'c' => string 'glop' (length=4)

array
  'a' => string 'hello' (length=5)
  'test' => string 'another one' (length=11)

Pero realmente no me gusta esta solución:

  • Perderás el phpdoc
  • Su IDE ya no podrá proporcionar ninguna pista... Lo cual es malo

Así que usaría esto sólo en casos muy específicos, para funciones con muchos parámetros opcionales, por ejemplo...

Pascal MARTIN avatar Aug 27 '2009 18:08 Pascal MARTIN

PHP 8 se lanzó el 26 de noviembre de 2020 con una nueva característica llamada argumentos con nombre .

En esta versión principal, los " parámetros con nombre " (también conocidos como " argumentos con nombre ") ofrecen a los desarrolladores algunas técnicas nuevas realmente interesantes al llamar a funciones nativas y personalizadas.

La función personalizada en esta pregunta ahora se puede llamar con el primer parámetro (porque no hay un valor predeterminado para ella) y luego solo se pasa el tercer parámetro usando parámetros con nombre como este: ( Demostración )

function foo($a, $b = '', $c = '') {
    echo $a . '&' . $b . '&' . $c;
}

foo("hello", c: "bar"); 
// output: hello&&bar

Observe que no era necesario declarar el segundo parámetro en la llamada a la función porque tiene un valor predeterminado definido: el valor predeterminado se usa automáticamente dentro del cuerpo de la función.

Parte de la belleza de esta nueva característica es que no necesita tener cuidado con el orden de los parámetros nombrados: el orden de su declaración es irrelevante. foo(c: "barra", a: "hola"); funciona igual. Tener la capacidad de "omitir" declaraciones y escribir parámetros declarativos mejorará la legibilidad de sus scripts. El único inconveniente de esta nueva característica es que habrá un poco más de sobrecarga en las llamadas a funciones, pero yo (y muchos otros) creo que los beneficios superan este "costo".

A continuación se muestra un ejemplo de una función nativa que omite el limitparámetro, escribe los parámetros fuera de su orden normal y declara una variable de referencia. ( Demostración )

echo preg_replace(
         subject: 'Hello 7',
         pattern: '/[a-z ]/',
         count: $counted,
         replacement: ''
     )
     . " & " . $counted;
// output: H7 & 5

Hay más que contar sobre esta nueva característica. ¡Incluso puedes usar una matriz asociativa para pasar los parámetros nombrados a la función donde se puede usar el operador spread/splat para descomprimir los datos!

(*observe la ligera diferencia al declarar la variable de referencia). ( Demostración )

$params = [
    'subject' => 'Hello 7',  // normally third parameter
    'pattern' => '/[a-z ]/', // normally first parameter
    // 'limit'               // normally fourth parameter, omitted for this demonstration; the default -1 will be used
    'count' => &$counted,    // normally fifth parameter
    //         ^-- don't forget to make it modifiable!
    'replacement' => '',     // normally second parameter
];
echo preg_replace(...$params) . " & " . $counted;
// same output as the previous snippet

El mismo comportamiento se puede disfrutar a través de call_user_func_array(). Demostración usando mi primera función de usuario declarada

call_user_func_array('foo', ['c' => 9, 'a' => 7]);
// output: 7&&9

Para obtener más información, aquí hay algunas pistas que explican más sobre esta característica y algunos errores comunes relacionados: (No tengo ninguna afiliación con los siguientes sitios)

  • https://wiki.php.net/rfc/named_params
  • https://stitcher.io/blog/php-8-named-arguments
  • https://stitcher.io/blog/why-we-need-named-params-in-php
mickmackusa avatar Nov 25 '2020 01:11 mickmackusa

PHP no admitía directamente parámetros con nombre.

En PHP, puedes utilizar un sustituto bastante razonable. El manejo de matrices de PHP es particularmente bueno y puede usar una matriz asociativa para pasar una matriz de parámetros, de la siguiente manera:

function foo($parms=[]) {
    $username = $parms['username'] ?? '…';
    $password = $parms['password'] ?? '…';
    $timeout  = $parms['timeout'] ?? '…';
}

foo(['timeout'=>10]);

Tenga en cuenta el uso del ??operador para permitir un valor predeterminado simple si el elemento de la matriz de entrada no existe. Antes de PHP 7, usabas ?:el cual es sutilmente diferente, pero en este caso da el mismo resultado.

Los parámetros no tan ingeniosos, pero con nombre, tienen otra función importante: le permiten trabajar con una gran cantidad de opciones sin una lista excesivamente larga de parámetros ordenados.

Una forma alternativa de escribir la función es utilizar la extractfunción:

function foo($parms=[]) {
    $username = '…';
    $password = '…';
    $timeout = '…';
    extract($parms,EXTR_IF_EXISTS);
}

Aquí la extractfunción copia los valores en las variables, pero solo si ya han sido definidos. Esto evita importar variables que no conocía.

Manngo avatar Apr 24 '2017 11:04 Manngo