Fue una decisión cerrada, pero los argumentos con nombre, también llamados parámetros con nombre, ¡son compatibles con PHP 8! En esta publicación, discutamos un poco sus pros y sus contras, pero déjame mostrarte primero cómo se ven con algunos ejemplos:

setcookie(
    name: 'prueba',
    expires: time() + 60 * 60 * 2,
);
class Cliente
{
    public function __construct(
        public string $nombre,
        public string $email,
        public int $edad,
    ) {}
}

$data = new CustomerData(
    nombre: $input['nombre'],
    email: $input['email'],
    edad: $input['edad'],
);
$data = new Cliente(...$customerRequest->validated());

Es posible que lo haya adivinado por los ejemplos: los argumentos con nombre le permiten pasar datos de entrada a una función, en función del nombre de su argumento en lugar del orden de los argumentos.

Yo diría que los argumentos con nombre son una gran característica que tendrá un impacto significativo en el desarrollo de aplicaciones con PHP. Sin embargo, probablemente se esté preguntando acerca de los detalles: ¿qué pasa si pasa un nombre incorrecto? ¿Qué pasa con esa sintaxis de distribución de matriz? Bueno, veamos todas esas preguntas en profundidad.

Digamos que esta característica fue muy debatida y hubo algunos argumentos en contra para no agregarlos. Sin embargo, diría que su beneficio supera con creces el miedo a los problemas de compatibilidad con versiones anteriores o las API infladas. A mi modo de ver, nos permitirán escribir código más limpio y flexible.

Por un lado, los argumentos con nombre le permiten omitir los valores predeterminados. Eche un vistazo de nuevo al ejemplo de la cookie:

setcookie(
    name: 'prueba',
    expires: time() + 60 * 60 * 2,
);

Realmente todos sus argumentos son:

setcookie ( 
    string $name, 
    string $value = "", 
    int $expires = 0, 
    string $path = "", 
    string $domain = "", 
    bool $secure = false, 
    bool $httponly = false,
) : bool

En el ejemplo que mostré, no necesitábamos establecer el valor de una cookie, pero sí necesitábamos establecer un tiempo de caducidad. Los argumentos con nombre hicieron que la llamada de este método fuera un poco más concisa:

Sin argumentos nombrados tendriamos que hacer algo como esto:

setcookie(
    'prueba',
    '',
    time() + 60 * 60 * 2,
);

Además de omitir argumentos con valores predeterminados, también existe la ventaja de tener claridad sobre qué variable hace qué; algo que es especialmente útil en funciones con firmas de métodos grandes. Ahora podríamos decir que muchos argumentos suelen ser un CodeSmell ; Todavía tenemos que lidiar con ellos pase lo que pase, por lo que es mejor tener una forma sensata de hacerlo, que nada en absoluto.

Con los conceptos básicos ya explicados, veamos qué pueden y qué no pueden hacer los argumentos con nombre.

En primer lugar, los argumentos con nombre se pueden combinar con argumentos sin nombre, también llamados argumentos ordenados. En ese caso, los argumentos ordenados siempre deben ir primero.

Tome nuestro ejemplo DTO de antes:

class Cliente
{
    public function __construct(
        public string $nombre,
        public string $email,
        public int $edad,
    ) {}
}

Podrías construirlo así:

$data = new Cliente(
    $input['nombre'],
    edad: $input['edad'],
    email: $input['email'],
);

Sin embargo, tener un argumento ordenado después de uno con nombre generaría un error:

$data = new Cliente(
    edad: $input['edad'],
    $input['nombre'], // ERROR!
    email: $input['email'],
);

A continuación, es posible utilizar la distribución de matrices en combinación con argumentos con nombre:

$input = [
    'edad' => 25,
    'nombre' => 'Ricardo',
    'email' => 'hola@ricardogeek.com',
];

$data = new Cliente(...$input);

Sin embargo, si faltan entradas requeridas en la matriz, o si hay una clave que no aparece como un argumento con nombre, se generará un error:

$input = [
    'edad' => 25,
    'nombre' => 'Ricardo',
    'email' => 'hola@ricardogeek.com',
    'unknownProperty' => 'La seccion que debes vigilar se esta incendiando',
];

$data = new Cliente(...$input); // ERROR

Es posible combinar argumentos con nombre y ordenados en una matriz de entrada, pero solo si los argumentos ordenados siguen la misma regla que antes: ¡deben ir primero!

$input = [
    'Ricardo',
    'edad' => 25,
    'email' => 'hola@ricardogeek.com',
];

$data = new Cliente(...$input);

Si está utilizando funciones variádicas, los argumentos con nombre se pasarán con su nombre de clave a la matriz de argumentos variádicos. Tome el siguiente ejemplo:

class Cliente
{
    public static function new(...$args): self
    {
        return new self(...$args);
    }

    public function __construct(
        public string $nombre,
        public string $email,
        public int $edad,
    ) {}
}

$data = Cliente::new(
    email: 'hola@ricardogeek.com',
    edad: 25,
    nombre: 'Ricardo',
);

En este caso, $args en CustomerData::new contendrá los siguientes datos:

[
    'edad' => 25,
    'email' => 'hola@ricardogeek.com',
    'nombre' => 'Ricardo',
]

Los atributos, también conocidos como anotaciones, también admiten argumentos con nombre:

class Subscriptor
{
    #[ListensTo(event: Producto::class)]
    public function onProductCreated(Producto $event) { /* … */ }
}

No es posible tener una variable como nombre de argumento:

$campo = 'edad';

$data = Cliente::new(
    $campo: 25,
);

Y, por último, los argumentos con nombre tratarán de forma pragmática los cambios de nombre durante la herencia. Toma este ejemplo:

interface EventListener {
    public function on($event, $handler);
}

class MyListener implements EventListener
{
    public function on($myEvent, $myHandler)
    {
        // …
    }
}

PHP permitirá silenciosamente cambiar el nombre de $event a $myEvent y $handler a $myHandler; pero si decide usar argumentos con nombre usando el nombre del padre, se producirá un error de tiempo de ejecución:

public function register(EventListener $listener)
{
    $listener->on(
        event: $this->event,
        handler: $this->handler, 
    );
}

Se eligió este enfoque pragmático para evitar un cambio radical importante cuando todos los argumentos heredados tendrían que mantener el mismo nombre. Me parece una buena solución.

Eso es todo lo que hay que decir acerca de los argumentos con nombre. Si desea conocer un poco más la historia detrás de algunas decisiones de diseño, lo animo a leer el RFC.

Categorized in: