Skip to content

Bucles ​

Los bucles repiten código: mostrar 50 productos, recorrer los resultados de una consulta, generar una tabla. En esta lección verás for, while, do-while y, sobre todo, foreach, el bucle que más usarás en PHP.

Concepto ​

Un bucle es como una lista de tareas en una fábrica: "por cada caja que llegue, ponle una etiqueta". En lugar de escribir la misma instrucción 100 veces, la escribes una vez y le dices cuántas veces (o hasta cuándo) repetirla.

BucleÚsalo cuando...
foreachRecorres un array u objeto iterable (lo más común)
forSabes cuántas repeticiones necesitas o necesitas un índice numérico
whileRepites mientras se cumpla una condición, sin saber cuántas veces
do-whileIgual que while, pero debe ejecutarse al menos una vez

for ​

php
<?php
// for (inicio; condición; incremento)
for ($i = 1; $i <= 5; $i++) {
    echo "Vuelta número $i<br>";
}

// Contar hacia atrás de 10 en 10
for ($i = 100; $i >= 0; $i -= 10) {
    echo $i . ' ';
}
// 100 90 80 70 60 50 40 30 20 10 0

Ejemplo útil: generar las opciones de un <select> de años.

php
<?php $anioActual = (int) date('Y'); ?>
<label for="anio">Año de nacimiento</label>
<select name="anio" id="anio">
    <?php for ($anio = $anioActual; $anio >= $anioActual - 100; $anio--): ?>
        <option value="<?= $anio ?>"><?= $anio ?></option>
    <?php endfor; ?>
</select>

while ​

Se repite mientras la condición sea verdadera. Útil cuando no sabes cuántas vueltas darás.

php
<?php
// ¿Cuántos años tardo en duplicar mi ahorro al 8 % anual?
$ahorro = 10000;
$meta = 20000;
$anios = 0;

while ($ahorro < $meta) {
    $ahorro *= 1.08;  // Crece 8 %
    $anios++;
}

echo "Tardarás $anios años. Tendrás $" . number_format($ahorro, 2);
// Tardarás 10 años. Tendrás $21,589.25

Lo verás mucho al leer resultados de base de datos:

php
<?php
// (Lo veremos a fondo en la lección de PDO)
while ($fila = $consulta->fetch()) {
    echo $fila['nombre'] . '<br>';
}
// fetch() devuelve false cuando ya no hay filas, y el bucle termina.

do-while ​

Ejecuta el bloque primero y luego pregunta. Siempre corre al menos una vez.

php
<?php
// Generar un código aleatorio que no empiece con 0
do {
    $codigo = (string) random_int(0, 999999);
    $codigo = str_pad($codigo, 6, '0', STR_PAD_LEFT); // Rellena con ceros a 6 dígitos
} while ($codigo[0] === '0');

echo "Tu código: $codigo";

foreach: el rey de PHP ​

Recorre cada elemento de un array sin preocuparte por índices.

php
<?php
$frutas = ['manzana', 'pera', 'mango'];

// Sólo el valor
foreach ($frutas as $fruta) {
    echo "Me gusta el/la $fruta<br>";
}

// Índice y valor
foreach ($frutas as $indice => $fruta) {
    echo ($indice + 1) . ". $fruta<br>";
}

Con arrays asociativos (clave => valor):

php
<?php
$precios = [
    'Café americano' => 35,
    'Capuchino'      => 48,
    'Té chai'        => 42,
];

foreach ($precios as $producto => $precio) {
    echo "$producto: $$precio<br>";
}

Con arrays de arrays (el formato típico de una consulta a base de datos):

php
<?php
$productos = [
    ['id' => 1, 'nombre' => 'Teclado',  'precio' => 650,  'stock' => 8],
    ['id' => 2, 'nombre' => 'Mouse',    'precio' => 320,  'stock' => 0],
    ['id' => 3, 'nombre' => 'Monitor',  'precio' => 3200, 'stock' => 3],
];
?>
<table border="1" cellpadding="6">
    <thead>
        <tr><th>Producto</th><th>Precio</th><th>Estado</th></tr>
    </thead>
    <tbody>
    <?php foreach ($productos as $p): ?>
        <tr>
            <td><?= htmlspecialchars($p['nombre']) ?></td>
            <td>$<?= number_format($p['precio'], 2) ?></td>
            <td><?= $p['stock'] > 0 ? 'Disponible' : 'Agotado' ?></td>
        </tr>
    <?php endforeach; ?>
    </tbody>
</table>

Destructuring en foreach ​

php
<?php
$coordenadas = [[19.43, -99.13], [20.67, -103.35]];

foreach ($coordenadas as [$lat, $lng]) {
    echo "Lat: $lat, Lng: $lng<br>";
}

$usuarios = [
    ['nombre' => 'Ana', 'email' => 'ana@mail.com'],
    ['nombre' => 'Beto', 'email' => 'beto@mail.com'],
];

foreach ($usuarios as ['nombre' => $nombre, 'email' => $email]) {
    echo "$nombre ($email)<br>";
}

Modificar elementos: por referencia ​

Por defecto, foreach trabaja con una copia de cada elemento. Para modificar el array original usa &:

php
<?php
$precios = [100, 200, 300];

foreach ($precios as &$precio) {
    $precio *= 1.16;  // Añade IVA al original
}
unset($precio); // ¡IMPORTANTE! Rompe la referencia al terminar

print_r($precios); // [116, 232, 348]

Error común

No hacer unset($precio) tras un foreach por referencia. La variable sigue apuntando al último elemento, y si luego la reutilizas en otro foreach, sobrescribirás ese elemento sin darte cuenta. Muchas veces es más claro usar array_map (lo verás en Arrays).

break y continue ​

php
<?php
$numeros = [4, 7, -1, 12, 0, 9];

// continue: salta a la siguiente vuelta
foreach ($numeros as $n) {
    if ($n <= 0) {
        continue; // Ignora negativos y cero
    }
    echo "$n ";
}
// 4 7 12 9

echo '<br>';

// break: sale del bucle por completo
$buscado = 12;
foreach ($numeros as $i => $n) {
    if ($n === $buscado) {
        echo "Encontré $buscado en la posición $i";
        break; // Ya no hace falta seguir buscando
    }
}

break 2 sale de dos bucles anidados a la vez:

php
<?php
$matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];

foreach ($matriz as $f => $fila) {
    foreach ($fila as $c => $valor) {
        if ($valor === 5) {
            echo "El 5 está en fila $f, columna $c";
            break 2;
        }
    }
}

Bucles anidados: tabla de multiplicar ​

php
<?php
declare(strict_types=1);

$tamano = 10;
?>
<table border="1" cellpadding="4" style="border-collapse: collapse; text-align: center">
    <?php for ($fila = 1; $fila <= $tamano; $fila++): ?>
        <tr>
            <?php for ($col = 1; $col <= $tamano; $col++): ?>
                <!-- Resaltamos la diagonal (cuadrados perfectos) -->
                <td style="<?= $fila === $col ? 'background:#ffe08a' : '' ?>">
                    <?= $fila * $col ?>
                </td>
            <?php endfor; ?>
        </tr>
    <?php endfor; ?>
</table>

Bucles infinitos

Si la condición de un while nunca se vuelve falsa, el script se cuelga hasta que PHP lo corta por tiempo (max_execution_time, 30 s por defecto). Asegúrate siempre de que algo dentro del bucle acerque la condición a su fin.

Buena práctica

No hagas consultas a la base de datos dentro de un bucle si puedes evitarlo (el famoso problema "N+1"). Trae todos los datos de una vez y luego recórrelos. Tu sitio será mucho más rápido.

Ejercicios ​

  1. Imprime los números del 1 al 30, pero sustituye los múltiplos de 3 por "Fizz", los de 5 por "Buzz" y los de ambos por "FizzBuzz".
  2. Dado un array de calificaciones [8, 9.5, 6, 10, 7.5], calcula el promedio con foreach (sin usar array_sum).
  3. Recorre este array y genera una lista HTML sólo con los usuarios activos: [['nombre' => 'Ana', 'activo' => true], ['nombre' => 'Luis', 'activo' => false], ['nombre' => 'Sofía', 'activo' => true]].
Ver solución
php
<?php
for ($i = 1; $i <= 30; $i++) {
    echo match (true) {
        $i % 15 === 0 => 'FizzBuzz',
        $i % 3 === 0  => 'Fizz',
        $i % 5 === 0  => 'Buzz',
        default       => $i,
    };
    echo '<br>';
}
php
<?php
$calificaciones = [8, 9.5, 6, 10, 7.5];
$suma = 0;

foreach ($calificaciones as $c) {
    $suma += $c;
}

$promedio = $suma / count($calificaciones);
echo 'Promedio: ' . round($promedio, 2); // 8.2
php
<?php
$usuarios = [
    ['nombre' => 'Ana', 'activo' => true],
    ['nombre' => 'Luis', 'activo' => false],
    ['nombre' => 'Sofía', 'activo' => true],
];
?>
<ul>
    <?php foreach ($usuarios as $u): ?>
        <?php if (!$u['activo']) continue; ?>
        <li><?= htmlspecialchars($u['nombre']) ?></li>
    <?php endforeach; ?>
</ul>

Resumen ​

  • foreach recorre arrays; es el bucle más usado en PHP.
  • for cuando conoces el número de vueltas; while cuando depende de una condición.
  • do-while garantiza al menos una ejecución.
  • continue salta a la siguiente vuelta; break sale del bucle (break 2 de dos niveles).
  • Para modificar el array en un foreach, usa & y luego unset().
  • En plantillas: foreach: ... endforeach; y for: ... endfor;.
  • Evita bucles infinitos y consultas a la base de datos dentro de bucles.

Academia Web — aprende, copia y construye.