PHPlay

Curso de PHP gratis · Capítulo 5 de 13 · con Agente Branch

Condicionales en PHP: if, else, switch y match

Un programa que siempre hace lo mismo sirve de poco. Con if, switch y match tu código decide qué hacer según los datos.

Si... entonces

if ejecuta un bloque de código solo si una condición es verdadera:

if (condición) {
    // se ejecuta si la condición es true
}

La condición se escribe entre paréntesis y el bloque entre llaves. Por convención, el contenido del bloque va indentado (4 espacios): PHP no lo necesita, pero las personas sí.

Puedes usar cualquier comparación (<, ==, ===...) o cualquier valor: PHP lo convierte a bool con las reglas que viste en el Laboratorio.

<?php
$bateria = 15;
if ($bateria < 20) {
    echo "¡Batería baja! Volviendo a la base\n";
}
if ($bateria > 90) {
    echo "Esto no se imprime\n";
}
echo "Fin de la comprobación\n";
Salida
¡Batería baja! Volviendo a la base
Fin de la comprobación

else y elseif

else es el "si no". elseif encadena más condiciones:

if ($nota >= 9) {
    ...
} elseif ($nota >= 5) {
    ...
} else {
    ...
}

PHP evalúa las condiciones en orden y ejecuta solo el primer bloque cuya condición sea verdadera. Los demás se saltan aunque también se cumplieran. Por eso el orden importa: pon primero los casos más concretos.

Usa la Lupa paso a paso para ver qué líneas se ejecutan y cuáles se saltan.

<?php
$nota = 7;
if ($nota >= 9) {
    echo "Sobresaliente\n";
} elseif ($nota >= 7) {
    echo "Notable\n";
} elseif ($nota >= 5) {
    echo "Aprobado\n";
} else {
    echo "Suspenso\n";
}
Salida
Notable
Pregunta

Si $nota = 9, pero hubiéramos puesto primero if ($nota >= 5) y luego elseif ($nota >= 9), ¿qué se imprimiría?

  1. Sobresaliente
  2. Aprobado
  3. Las dos
Ver respuesta

B. Aprobado

La primera condición (9 >= 5) ya es verdadera: se ejecuta ese bloque y el resto se salta. El orden importa.

Verdades a medias

En un if puedes poner cualquier valor, no solo comparaciones: if ($cantidad). PHP lo convierte a bool: es false si vale 0, 0.0, "", "0", [] o null.

Es cómodo, pero peligroso. Imagina que $cantidad viene de un formulario y vale "0": if ($cantidad) lo trata como "no hay cantidad". A veces es lo que quieres... y a veces es un bug.

Para comprobar si una variable existe, usa isset(); para comprobar si está "vacía" (no existe o es falsa), empty().

Truco

Sé explícito: if ($cantidad > 0) o if ($nombre !== "") expresan mejor tu intención que if ($cantidad).

<?php
$cantidad = "0";
if ($cantidad) {
    echo "Hay pedido\n";
} else {
    echo "No hay pedido (¿seguro?)\n";
}
var_dump(isset($cantidad), empty($cantidad));
var_dump(isset($nada), empty($nada));
Salida
No hay pedido (¿seguro?)
bool(true)
bool(true)
bool(false)
bool(true)

Combinar condiciones

Con && (y), || (o) y ! (no) construyes condiciones complejas:

if ($edad >= 18 && $tieneEntrada) { ... }
if ($esFestivo || $esDomingo) { ... }
if (!$lloviendo) { ... }

Usa paréntesis para que se entienda el orden: ($a || $b) && $c.

Recuerda el cortocircuito: en $divisor != 0 && $total / $divisor > 2, si el divisor es 0 la división nunca se ejecuta. El orden de las condiciones puede evitar errores.

<?php
$edad = 16;
$conPadres = true;
if ($edad >= 18 || ($edad >= 14 && $conPadres)) {
    echo "Puede entrar al molino\n";
}
$divisor = 0;
if ($divisor != 0 && 10 / $divisor > 2) {
    echo "Grande\n";
} else {
    echo "Sin división peligrosa\n";
}
Salida
Puede entrar al molino
Sin división peligrosa

La trampa del =

El bug más famoso de las condiciones: escribir = (asignar) en vez de == (comparar).

if ($x = 5) { ... }

Esto no compara: guarda 5 en $x, y como una asignación devuelve el valor asignado (5, que es verdadero), el if se cumple siempre. Y encima has machacado $x.

Pergamino del porque

¿Por qué PHP lo permite? Porque a veces es útil asignar dentro de una condición (lo verás con los bucles). Pero el 99% de las veces es un error. Algunos programadores escriben if (5 == $x) ("condición Yoda") para que un = olvidado dé error, porque no se puede asignar a un 5.

<?php
$x = 1;
if ($x = 5) {
    echo "¡Siempre entra! Y ahora x vale $x\n";
}
$y = 1;
if ($y == 5) {
    echo "No entra\n";
} else {
    echo "Comparación correcta, y sigue valiendo $y\n";
}
Salida
¡Siempre entra! Y ahora x vale 5
Comparación correcta, y sigue valiendo 1

switch

switch compara un valor con varios casos:

switch ($dia) {
    case 1:
        echo "Lunes";
        break;
    case 2:
        echo "Martes";
        break;
    default:
        echo "Otro día";
}

Dos cosas que debes saber:

  1. Hace falta break. Sin él, la ejecución "se cae" al siguiente case (fall-through) y ejecuta su código también. A veces se hace a propósito para agrupar casos.
  2. Compara con == (débil), no con ===. Así que switch ("1") entra en case 1:.
<?php
$dia = 2;
switch ($dia) {
    case 1:
        echo "Lunes\n";
        break;
    case 2:
    case 3:
        echo "Martes o miércoles\n";
        break;
    default:
        echo "Otro día\n";
}
switch ("1") {
    case 1:
        echo "switch usa ==\n";
        break;
}
Salida
Martes o miércoles
switch usa ==

match (PHP 8)

match es el hermano moderno de switch, y es mejor en casi todo:

$texto = match ($dia) {
    1 => "Lunes",
    2, 3 => "Martes o miércoles",
    default => "Otro día",
};
  • Es una expresión: devuelve un valor que puedes guardar o imprimir.
  • Compara con === (estricto).
  • No necesita break: nunca se "cae" al siguiente brazo.
  • Si ningún brazo coincide y no hay default, lanza un error (UnhandledMatchError) en vez de seguir en silencio.

Truco: match (true) permite usar condiciones en los brazos: $n < 5 => ....

<?php
$dia = 3;
echo match ($dia) {
    1 => "Lunes",
    2, 3 => "Martes o miércoles",
    default => "Otro día",
}, "\n";
$peso = 42;
$talla = match (true) {
    $peso < 10 => "pequeño",
    $peso < 50 => "mediano",
    default => "grande",
};
echo "Saco $talla\n";
echo match ("1") { 1 => "igual", default => "match usa ===" }, "\n";
Salida
Martes o miércoles
Saco mediano
match usa ===
Pregunta

¿Qué diferencia NO es cierta entre switch y match?

  1. match compara con ===
  2. match devuelve un valor
  3. match necesita break en cada brazo
  4. Sin coincidencia ni default, match lanza un error
Ver respuesta

C. match necesita break en cada brazo

match nunca necesita break: cada brazo es independiente. Es switch el que lo necesita.

El ternario

Para decisiones cortas que eligen entre dos valores, el operador ternario:

$estado = $bateria > 50 ? "ok" : "cargar";

Se lee "¿condición? valor si sí : valor si no".

Su versión corta ?: (el operador Elvis) devuelve el primer valor si es verdadero y si no el segundo: $nombre ?: "anónimo".

Y no lo confundas con ??: ?? mira si existe y no es null; ?: mira si es verdadero (así que 0 o "" pasan al segundo).

Cuidado

No anides ternarios sin paréntesis: PHP 8 lo prohíbe porque era imposible de leer.

<?php
$bateria = 30;
$estado = $bateria > 50 ? "ok" : "cargar";
echo "Estado: $estado\n";
$apodo = "";
echo $apodo ?: "anónimo", "\n";
echo $apodo ?? "anónimo", "|\n";
Salida
Estado: cargar
anónimo
|

BIT-8 toma decisiones

Con condiciones, BIT-8 puede reaccionar a lo que tiene debajo:

  • puede_cosechar() devuelve true si hay algo maduro.
  • que_hay() devuelve el cultivo: HIERBA, ZANAHORIA... o null si no hay nada.
  • suelo() devuelve "cesped" o "tierra".

(Para usar que_hay() y suelo() en tu granja necesitarás el Escáner de suelo del Taller.)

Cuidado

Si cosechas algo que no está maduro, lo pierdes. ¡Pregunta antes!

<?php
if (puede_cosechar()) {
    cosechar();
} else {
    decir("Aún está verde");
}

$planta = que_hay();
if ($planta === ZANAHORIA) {
    decir("¡Una zanahoria!");
} elseif ($planta === null) {
    decir("Aquí no hay nada");
}

Ejercicios de Condicionales en PHP resueltos

Intenta resolverlos antes de mirar la solución. En el juego puedes ejecutarlos y comprobarlos automáticamente.

Misión del dron 1. Solo lo maduro

En la columna de BIT-8 hay hierba madura y hierba verde mezcladas. Si cosechas la verde, se estropea.

BIT-8 está en (0, 0). Recorre su columna hacia el NORTE (3 casillas) y cosecha solo la hierba madura. No cortes nada verde.

Esta misión mueve al dron BIT-8 por un campo de cultivo: juégala en PHPlay para ver tu código animado.

Pistas
  • En cada casilla: if (puede_cosechar()) { cosechar(); } y luego mover(NORTE);.
  • Tendrás que repetir el bloque tres veces. (En el Molino aprenderás a no repetirte.)
Ver solución
<?php
if (puede_cosechar()) {
    cosechar();
}
mover(NORTE);
if (puede_cosechar()) {
    cosechar();
}
mover(NORTE);
if (puede_cosechar()) {
    cosechar();
}

Encargo 2. El control del puente

El Guardia te deja escribir sus normas. Las variables $edad (int) y $salvoconducto (bool) ya existen.

Imprime:

  • Pasa si la edad es 18 o más.
  • Pasa con escolta si tiene 14 o más y tiene salvoconducto.
  • No pasa en cualquier otro caso.
Pistas
  • Empieza por el caso más general: if ($edad >= 18).
  • Después: elseif ($edad >= 14 && $salvoconducto).
Ver solución
<?php
if ($edad >= 18) {
    echo "Pasa";
} elseif ($edad >= 14 && $salvoconducto) {
    echo "Pasa con escolta";
} else {
    echo "No pasa";
}

Encargo 3. Notas con match

La escuela del valle necesita convertir notas numéricas en palabras. $nota (de 0 a 10) ya existe.

Usando match, imprime:

  • Suspenso si es menor que 5
  • Aprobado si es 5 o 6
  • Notable si es 7 u 8
  • Sobresaliente si es 9 o 10
Pistas
  • echo match (true) { $nota < 5 => "Suspenso", ... };
  • También puedes listar valores: 5, 6 => "Aprobado".
Ver solución
<?php
echo match (true) {
    $nota < 5 => "Suspenso",
    $nota <= 6 => "Aprobado",
    $nota <= 8 => "Notable",
    default => "Sobresaliente",
};

Predicción 4. El switch que se cae

Un aprendiz olvidó algunos break. ¿Qué imprime su programa?

Elige la salida.

<?php
$dia = 2;
switch ($dia) {
    case 1:
        echo "Lunes ";
    case 2:
        echo "Martes ";
    case 3:
        echo "Miércoles ";
        break;
    default:
        echo "Otro";
}
  1. Martes
  2. Martes Miércoles
  3. Lunes Martes Miércoles
  4. Martes Miércoles Otro
Ver solución
Martes Miércoles 

Entra en el case 2 y, sin break, cae al 3, donde por fin hay un break.

Caza de bugs 5. El if tramposo

Este programa debería avisar solo si el pedido es de 5 sacos. Pero siempre dice "grande" y encima cambia el pedido.

Arregla la condición para que, con $pedido = 0, imprima exactamente:

Pedido pequeño
Pedido: 0

Código de partida:

<?php
$pedido = 0;
if ($pedido = 5) {
    echo "Pedido grande\n";
} else {
    echo "Pedido pequeño\n";
}
echo "Pedido: $pedido\n";
Pistas
  • = guarda un valor. Para comparar usa == o, mejor, ===.
Ver solución
<?php
$pedido = 0;
if ($pedido === 5) {
    echo "Pedido grande\n";
} else {
    echo "Pedido pequeño\n";
}
echo "Pedido: $pedido\n";

Misión del dron 6. Siembra condicional

En la columna de BIT-8 hay casillas de césped con hierba madura y casillas de tierra vacía.

Recorre la columna (3 casillas hacia el NORTE). En cada casilla: si el suelo es "tierra", planta una ZANAHORIA; si no, cosecha si se puede. No debe fallar ninguna acción.

Esta misión mueve al dron BIT-8 por un campo de cultivo: juégala en PHPlay para ver tu código animado.

Pistas
  • if (suelo() === "tierra") { plantar(ZANAHORIA); } elseif (puede_cosechar()) { cosechar(); }
Ver solución
<?php
if (suelo() === "tierra") {
    plantar(ZANAHORIA);
} elseif (puede_cosechar()) {
    cosechar();
}
mover(NORTE);
if (suelo() === "tierra") {
    plantar(ZANAHORIA);
} elseif (puede_cosechar()) {
    cosechar();
}
mover(NORTE);
if (suelo() === "tierra") {
    plantar(ZANAHORIA);
} elseif (puede_cosechar()) {
    cosechar();
}

Chuleta: lo esencial

  • if (cond) { } elseif (cond) { } else { }: se ejecuta solo el primer bloque verdadero.
  • Valores falsos: false 0 0.0 "" "0" [] null. Sé explícito: if ($n > 0).
  • isset($x): existe y no es null. empty($x): no existe o es falso.
  • &&, ||, ! con paréntesis. El cortocircuito puede proteger operaciones.
  • if ($x = 5) asigna (siempre verdadero). Compara con == o ===.
  • switch: compara con ==, necesita break (si no, fall-through), default.
  • match: expresión, compara con ===, sin break, error si no hay coincidencia. match (true) para rangos.
  • Ternario: cond ? a : b. Elvis: $a ?: $b. Null coalescing: $a ?? $b.