Lección 13 de 75 10 min de lectura

Control de Flujo: break, continue y return

A veces necesitas más control sobre cómo se ejecutan tus bucles. Las sentencias break y continue te permiten salir de un bucle o saltar a la siguiente iteración cuando ciertas condiciones se cumplen.

La sentencia break

break termina inmediatamente la ejecución del bucle actual. El programa continúa con el código que viene después del bucle.

PHP
<?php

// Buscar un elemento y salir al encontrarlo
$numeros = [4, 8, 15, 16, 23, 42];
$buscar = 16;
$encontrado = false;

foreach ($numeros as $indice => $numero) {
    if ($numero === $buscar) {
        $encontrado = true;
        echo "Encontrado en posición $indice\n";
        break; // Sale del bucle inmediatamente
    }
    echo "Buscando... $numero\n";
}

// Salida:
// Buscando... 4
// Buscando... 8
// Buscando... 15
// Encontrado en posición 3

// Sin break, seguiría iterando innecesariamente

La sentencia continue

continue salta el resto del código en la iteración actual y pasa directamente a la siguiente iteración del bucle.

PHP
<?php

// Imprimir solo números pares
for ($i = 1; $i <= 10; $i++) {
    if ($i % 2 !== 0) {
        continue; // Salta los impares
    }
    echo "$i "; // Solo se ejecuta para pares
}
// Salida: 2 4 6 8 10

// Procesar solo elementos válidos
$datos = ['Ana', '', 'Luis', null, 'María', ''];

foreach ($datos as $nombre) {
    if (empty($nombre)) {
        continue; // Salta valores vacíos
    }
    echo "Procesando: $nombre\n";
}
// Procesa solo: Ana, Luis, María

// Útil para filtrar sin crear nuevos arrays
$productos = [
    ['nombre' => 'Laptop', 'stock' => 5],
    ['nombre' => 'Mouse', 'stock' => 0],
    ['nombre' => 'Teclado', 'stock' => 12],
    ['nombre' => 'Monitor', 'stock' => 0],
];

echo "Productos disponibles:\n";
foreach ($productos as $producto) {
    if ($producto['stock'] === 0) {
        continue; // Ignora productos sin stock
    }
    echo "- {$producto['nombre']} ({$producto['stock']} unidades)\n";
}

break y continue en bucles anidados

Cuando tienes bucles dentro de bucles, puedes especificar cuántos niveles quieres saltar con break N o continue N.

PHP
<?php

// Buscar en una matriz bidimensional
$matriz = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
];
$buscar = 5;
$posicion = null;

foreach ($matriz as $fila => $columnas) {
    foreach ($columnas as $col => $valor) {
        if ($valor === $buscar) {
            $posicion = [$fila, $col];
            break 2; // Sale de AMBOS bucles
        }
    }
}

echo "Encontrado en fila $posicion[0], columna $posicion[1]";
// Encontrado en fila 1, columna 1

// Sin "break 2", solo saldría del bucle interno
// y seguiría con las siguientes filas
PHP
<?php

// continue 2 para saltar al siguiente elemento del bucle externo
$categorias = [
    'Frutas' => ['manzana', 'ERROR', 'pera'],
    'Verduras' => ['zanahoria', 'lechuga'],
    'Lácteos' => ['ERROR', 'leche', 'queso'],
];

foreach ($categorias as $categoria => $items) {
    echo "\n$categoria:\n";

    foreach ($items as $item) {
        if ($item === 'ERROR') {
            echo "  - Error encontrado, saltando categoría...\n";
            continue 2; // Salta al siguiente $categoria
        }
        echo "  - $item\n";
    }

    echo "  [Categoría completa]\n";
}

// Salida:
// Frutas:
//   - manzana
//   - Error encontrado, saltando categoría...
// Verduras:
//   - zanahoria
//   - lechuga
//   [Categoría completa]
// Lácteos:
//   - Error encontrado, saltando categoría...
Niveles de anidación

break 1 es lo mismo que break (sale del bucle actual). break 2 sale de dos niveles de bucles anidados, y así sucesivamente. Lo mismo aplica para continue.

break y continue en switch

break también se usa en switch para evitar el fall-through. Cuando tienes un switch dentro de un bucle, ten cuidado con qué estructura estás terminando.

PHP
<?php

$comandos = ['procesar', 'saltar', 'procesar', 'terminar', 'procesar'];

foreach ($comandos as $comando) {
    switch ($comando) {
        case 'procesar':
            echo "Procesando...\n";
            break; // Sale del switch, NO del foreach

        case 'saltar':
            echo "Saltando...\n";
            continue 2; // Salta a la siguiente iteración del foreach

        case 'terminar':
            echo "Terminando todo.\n";
            break 2; // Sale del switch Y del foreach
    }

    echo "Fin de iteración\n";
}

// Salida:
// Procesando...
// Fin de iteración
// Saltando...           (no imprime "Fin de iteración")
// Procesando...
// Fin de iteración
// Terminando todo.      (no continúa con más comandos)

return en funciones

Dentro de una función, return termina la ejecución de la función completamente, incluyendo cualquier bucle que esté en ejecución.

PHP
<?php

function buscarUsuario(array $usuarios, int $id): ?array
{
    foreach ($usuarios as $usuario) {
        if ($usuario['id'] === $id) {
            return $usuario; // Termina la función inmediatamente
        }
    }

    return null; // Solo se ejecuta si no se encontró
}

// Early return para validación
function procesarPedido(array $pedido): string
{
    if (empty($pedido['items'])) {
        return 'Error: Pedido sin items';
    }

    if ($pedido['total'] <= 0) {
        return 'Error: Total inválido';
    }

    // Lógica principal solo si pasa las validaciones
    foreach ($pedido['items'] as $item) {
        // Procesar cada item...
    }

    return 'Pedido procesado correctamente';
}

Ejemplos prácticos

PHP
<?php

// 1. Limitar resultados (como LIMIT en SQL)
$productos = obtenerTodosLosProductos();
$limite = 10;
$contador = 0;

foreach ($productos as $producto) {
    if ($contador >= $limite) {
        break;
    }

    mostrar($producto);
    $contador++;
}

// 2. Procesar hasta encontrar error
$registros = obtenerRegistros();
$errores = [];

foreach ($registros as $registro) {
    $resultado = validar($registro);

    if (!$resultado['valido']) {
        $errores[] = $resultado['error'];

        // Opción A: Detener al primer error
        break;

        // Opción B: Continuar y recopilar todos los errores
        // continue;
    }

    guardar($registro);
}

// 3. Paginación manual
$pagina = 2;
$porPagina = 10;
$inicio = ($pagina - 1) * $porPagina;
$fin = $inicio + $porPagina;
$contador = 0;

foreach ($items as $item) {
    if ($contador < $inicio) {
        $contador++;
        continue; // Salta items antes de la página actual
    }

    if ($contador >= $fin) {
        break; // Detiene al llegar al límite
    }

    mostrar($item);
    $contador++;
}

// 4. Buscar duplicados
$valores = [1, 5, 3, 5, 7, 2, 5];
$duplicados = [];
$vistos = [];

foreach ($valores as $valor) {
    if (in_array($valor, $vistos)) {
        if (!in_array($valor, $duplicados)) {
            $duplicados[] = $valor;
        }
        continue; // Ya lo procesamos
    }
    $vistos[] = $valor;
}

print_r($duplicados); // [5]

Buenas prácticas

PHP
<?php

// ✓ BIEN: break/continue al inicio para casos especiales
foreach ($usuarios as $usuario) {
    if ($usuario['bloqueado']) {
        continue;
    }

    if ($usuario['rol'] === 'admin') {
        break; // Encontramos lo que buscábamos
    }

    // Lógica principal clara, sin anidación profunda
    procesarUsuario($usuario);
}

// ✗ MAL: Lógica difícil de seguir con múltiples break/continue
foreach ($datos as $dato) {
    if ($condicion1) {
        if ($condicion2) {
            continue;
        }
        // código...
        if ($condicion3) {
            break;
        }
    } else {
        // más código...
        if ($condicion4) {
            continue;
        }
    }
}

// ✓ BIEN: Extraer a función si la lógica es compleja
function deberíaProcesar($dato): bool
{
    if ($dato['inactivo']) return false;
    if ($dato['expirado']) return false;
    return true;
}

foreach ($datos as $dato) {
    if (!deberíaProcesar($dato)) {
        continue;
    }
    procesar($dato);
}

// ✓ BIEN: Evitar anidación con early continues
foreach ($pedidos as $pedido) {
    // Filtros al inicio
    if ($pedido['cancelado']) continue;
    if ($pedido['procesado']) continue;
    if ($pedido['total'] <= 0) continue;

    // Código principal limpio
    enviarConfirmacion($pedido);
    actualizarInventario($pedido);
    marcarComoProcesado($pedido);
}
Evita goto

PHP tiene una sentencia goto, pero su uso está muy desaconsejado. Hace el código difícil de seguir y mantener. Siempre hay mejores alternativas con funciones, bucles y estructuras de control normales.

Ejercicios

Ejercicio 1: Buscar y salir con break

Dado el array $numeros = [3, 7, 2, 9, 4, 6], busca el numero 9. Cuando lo encuentres, imprime su posicion y sal del bucle con break.

Ver solucion
<?php

declare(strict_types=1);

$numeros = [3, 7, 2, 9, 4, 6];
$buscar = 9;

foreach ($numeros as $indice => $numero) {
    if ($numero === $buscar) {
        echo "Encontrado $buscar en la posicion $indice\n";
        break;
    }
    echo "Revisando posicion $indice: $numero\n";
}

Ejercicio 2: Filtrar con continue

Dado el array $edades = [15, 22, 17, 30, 12, 25], usa continue para imprimir solo las edades de mayores de edad (18 o mas).

Ver solucion
<?php

declare(strict_types=1);

$edades = [15, 22, 17, 30, 12, 25];

echo "Mayores de edad:\n";

foreach ($edades as $edad) {
    if ($edad < 18) {
        continue;
    }
    echo "- $edad años\n";
}

Ejercicio 3: Procesar hasta limite

Dado el array $items = [5, 10, 15, 20, 25, 30], suma los valores pero detente (break) cuando la suma supere 30. Imprime la suma final.

Ver solucion
<?php

declare(strict_types=1);

$items = [5, 10, 15, 20, 25, 30];
$suma = 0;

foreach ($items as $item) {
    if ($suma + $item > 30) {
        echo "Limite alcanzado, no se suma $item\n";
        break;
    }
    $suma += $item;
    echo "Sumado $item, total: $suma\n";
}

echo "Suma final: $suma\n";

¿Te está gustando el curso?

Tenemos cursos premium con proyectos reales y soporte personalizado.

Descubrir cursos premium