PHP 8 trajo match, y mucha gente lo ve como «un switch
más corto». Es más que eso: compara de forma estricta, devuelve un valor, no necesita
break y te avisa si se te olvida un caso. Vamos a ver las diferencias con
ejemplos sencillos y cuándo sigue teniendo sentido el switch.
Explicación
El mismo código, primero con switch:
switch ($status) {
case 'pending':
$label = 'Pendiente';
break;
case 'paid':
$label = 'Pagado';
break;
default:
$label = 'Desconocido';
}
Y con match:
$label = match ($status) {
'pending' => 'Pendiente',
'paid' => 'Pagado',
default => 'Desconocido',
};
De nueve líneas a cinco, y sin repetir $label = en cada caso. Pero lo
importante no es que sea más corto, sino que se comporta distinto.
Las diferencias
1. match devuelve un valor
switch ejecuta código; match es una expresión, como una suma o una
llamada a función. Por eso lo puedes asignar, devolver o pasar como argumento
directamente:
return match ($status) {
'pending' => 'Pendiente',
'paid' => 'Pagado',
default => 'Desconocido',
};
2. Compara con ===, no con ==
switch compara «por encima» (==) y match de forma
estricta (===): el valor y el tipo tienen que coincidir.
$page = '1'; // viene de la URL: siempre es un string
switch ($page) {
case 1:
echo 'primera'; // entra: '1' == 1
break;
}
echo match ($page) {
1 => 'primera',
default => 'otra', // sale 'otra': '1' !== 1
};
Casi siempre es lo que quieres, pero ojo con lo que llega de formularios y URLs: si
comparas con números, convierte antes con (int) $page.
3. No hay break (ni bugs por olvidarlo)
En un switch, si te olvidas un break, la ejecución «se cae» al
caso siguiente:
switch ($status) {
case 'pending':
$label = 'Pendiente';
// falta el break...
case 'paid':
$label = 'Pagado'; // ...y un pedido pendiente acaba como «Pagado»
break;
}
En match cada caso es independiente: se ejecuta uno y se acabó.
4. Si no encaja ningún caso, falla
Un switch sin default que no encuentra nada simplemente no hace
nada, y sigues adelante con una variable sin asignar. match lanza un
UnhandledMatchError:
$label = match ($status) {
'pending' => 'Pendiente',
'paid' => 'Pagado',
};
// con $status = 'shipped':
// UnhandledMatchError: Unhandled match case 'shipped'
Parece peor, pero es mejor: te enteras del caso que se te olvidó en la línea exacta, en vez
de tres pantallas más allá. Con enums es donde más luce: si
añades un caso nuevo al enum y no lo contemplas, el match te lo dice.
5. Varios valores en un mismo caso
Se separan con comas:
$canCancel = match ($status) {
'pending', 'paid' => true,
'shipped', 'delivered' => false,
};
6. Condiciones con match (true)
Para rangos o condiciones, el truco es comparar con true: gana el primer caso
que se cumpla.
$discount = match (true) {
$total >= 100 => 20,
$total >= 50 => 10,
default => 0,
};
El orden importa: si pusieras primero $total >= 50, un total de 150 se
quedaría con el 10 %.
Cuándo sigue siendo mejor switch
Cada caso de match es una sola expresión. Si en cada caso
tienes que hacer varias cosas, switch se lee mejor:
switch ($event) {
case 'order_paid':
$this->mailer->sendReceipt($order);
$this->stock->reserve($order);
$this->logger->info('Order paid');
break;
case 'order_cancelled':
$this->stock->release($order);
$this->mailer->sendCancellation($order);
break;
}
Con match tendrías que meter cada bloque en una función aparte. A veces es
buena idea, pero no siempre compensa.
El resumen
switch |
match |
|
|---|---|---|
| Devuelve un valor | No | Sí |
| Comparación | == |
=== |
Necesita break |
Sí | No |
| Si no encaja nada | No hace nada | Lanza un error |
| Varias líneas por caso | Sí | No |
La regla: si estás eligiendo un valor, match; si estás eligiendo qué
hacer, switch.
Y ya está
La próxima vez que escribas un switch que solo asigna una variable en cada
caso, pásalo a match: será más corto, no tendrá break que
olvidar y te avisará del caso que falte. Y si te pica la curiosidad por otros atajos del
lenguaje, mira los operadores que casi
nadie usa.