Menu

foreach en PHP: clave y valor, índice y referencia

foreach ($array as $value) visita cada elemento de un array, y foreach ($array as $key => $value) te da también la clave. Incluye cómo obtener el índice, cambiar valores por referencia y la trampa de unset(), break y continue, arrays anidados, list() en foreach y generar HTML.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

foreach ($array as $value) ejecuta el bloque una vez por cada elemento, con $value igual al elemento actual. Para obtener también la clave, escribe foreach ($array as $key => $value).

foreach funciona con cualquier array, sean cuales sean sus claves, y nunca tienes que gestionar un contador ni comprobar una longitud. Es el bucle que más vas a escribir en PHP.

Recorrer claves y valores

En $key => $value, los nombres los eliges tú: $name => $age, $id => $user, $k => $v. En una lista, las claves son las posiciones 0, 1, 2. En un array asociativo, son las claves de texto que definiste.

El último bucle muestra un detalle que sorprende: una clave de texto que parece un número entero, como "1", se guarda como el entero 1. "01" no es un entero canónico, así que se queda como cadena.

Obtener el índice en foreach

En una lista, la clave es el índice, así que foreach ($items as $i => $item) es todo lo que necesitas. En un array asociativo no hay posición numérica, así que lleva un contador. Para tratar de forma distinta el primer o el último elemento, compara la clave con array_key_first() o array_key_last().

El último bucle imprime una coma entre los nombres pero no después del último. Para ese trabajo concreto, implode(', ', array_keys($scores)) es más corto; la comprobación con array_key_last() es para cuando la última vuelta necesita una lógica distinta, no solo otro separador.

Cambiar valores del array en foreach (por referencia)

$value es una copia. Asignarle algo no cambia nada en el array. Para cambiar el array, recorre por referencia con &$value o escribe a través de la clave.

Las dos funcionan. La versión con la clave no deja ningún estado oculto tras el bucle, y por eso muchos equipos la prefieren. Para construir un array nuevo en lugar de cambiar uno, array_map() es otra opción.

Una pregunta relacionada: ¿qué pasa si añades elementos mientras recorres? Un foreach normal recorre el array tal como estaba al empezar el bucle, así que un $prices[] = ... dentro de él no crea vueltas extra. Un bucle por referencia recorre el array vivo y sí visita los elementos nuevos.

La trampa de unset() con foreach por referencia

Después de foreach ($arr as &$v), la variable $v sigue siendo una referencia al último elemento del array. Si luego reutilizas el nombre $v en un bucle normal, cada vuelta escribe en ese último elemento. Ejecuta esto y mira el último elemento:

El segundo bucle asigna A, luego B y luego el propio valor del último elemento a $letters[2], y en la última vuelta esa posición ya contiene B. La solución es una línea: pon unset($v); justo después de cada foreach por referencia.

break y continue en foreach

break sale del bucle y continue salta al siguiente elemento. Un patrón habitual es buscar: recorres hasta encontrar lo que necesitas y luego haces break para no comprobar el resto del array.

En bucles anidados, break 2 sale del bucle interior y del que lo rodea, y continue 2 salta a la siguiente vuelta del bucle exterior.

Arrays anidados y foreach con list()

Las filas de datos son arrays dentro de un array. Recorre las filas y luego cada fila, o saca los campos directamente en la línea del foreach con desestructuración: [$a, $b] para listas, ['key' => $var] para filas asociativas. list($a, $b) es la forma antigua de escribir [$a, $b].

La página de desestructuración explica más sobre la sintaxis [...] =, incluidos los elementos que se saltan y los patrones anidados.

Generar una lista o una tabla HTML con foreach

En una plantilla, la forma con dos puntos foreach (...): y endforeach; mantiene legible el bucle entre etiquetas. Este bloque construye una tabla, y los encabezados de las columnas son enlaces: haz clic en uno en la pestaña Página y el mismo script se ejecuta otra vez con $_GET['sort'] definido, así que las filas vuelven en otro orden.

Dos hábitos que vale la pena copiar de este bloque: el valor de sort que llega en la URL se comprueba contra una lista de columnas permitidas antes de usarlo, y cada valor que se imprime en el HTML y podría contener texto del usuario pasa por htmlspecialchars().

foreach sobre null, un array vacío o un objeto

Un array vacío no da problemas: el cuerpo no se ejecuta nunca. null, una cadena o un número sí: PHP imprime un warning y se salta el bucle. Para $tags = null; foreach ($tags as $tag) imprime:

Warning: foreach() argument must be of type array|object, null given in /var/www/html/index.php on line 4

Esto pasa sobre todo con datos que a veces faltan, como un campo opcional de un JSON decodificado. Usa un array vacío por defecto con ??:

foreach ($data['tags'] ?? [] as $tag) {
    echo $tag;
}

El object de ese mensaje es real: foreach sobre un objeto visita sus propiedades visibles desde donde se ejecuta el bucle (fuera de la clase, las públicas), con el nombre de la propiedad como clave. Las clases que implementan Iterator o IteratorAggregate, y los generadores, deciden por sí mismas qué ve un foreach.

foreach vs for vs array_map

UsaCuándo
foreachQuieres cada elemento, con o sin su clave. Funciona con cualquier array, lista o asociativo.
forCuentas (del 1 al 100, uno de cada dos elementos) o necesitas los vecinos por índice ($a[$i - 1]). Consulta el bucle for.
array_map()Construyes un array nuevo transformando cada elemento, a menudo en una línea con fn.
array_filter()Te quedas solo con los elementos que pasan una prueba.

Una forma rápida de decidir: si el cuerpo del bucle solo calcula un valor nuevo por elemento, array_map(fn($x) => $x * 2, $a) lo dice en una línea. Si tiene efectos secundarios (imprimir, guardar, contar varias cosas a la vez) o necesita break, escribe el foreach.

Preguntas frecuentes

¿Cómo obtengo la clave y el valor en un bucle foreach de PHP?

Usa la forma con =>: foreach ($array as $key => $value) { echo "$key: $value"; }. En una lista simple, la clave es el índice (0, 1, 2); en un array asociativo es la clave de texto, como 'name'.

¿Cómo obtengo el índice en un bucle foreach de PHP?

En una lista, la clave ya es el índice: foreach ($items as $i => $item). En un array asociativo, lleva tu propio contador: pon $i = 0; antes del bucle y $i++ al final de cada vuelta. array_key_first() y array_key_last() te dicen qué clave es la primera o la última.

¿Cómo modifico los valores de un array dentro de foreach en PHP?

Recorre por referencia con &: foreach ($prices as &$price) { $price *= 2; } unset($price);. O escribe a través de la clave: foreach ($prices as $key => $price) { $prices[$key] = $price * 2; }. Un simple $price = ... solo cambia una copia.

¿Por qué foreach por referencia en PHP duplica el último elemento?

Después de foreach ($arr as &$v), $v sigue siendo una referencia al último elemento. Un segundo foreach ($arr as $v) escribe entonces cada valor en esa última posición, que acaba repitiendo el penúltimo valor. Llama a unset($v); justo después del bucle por referencia.

¿Cómo salgo de un bucle foreach en PHP?

break; detiene el bucle inmediatamente y continue; salta al siguiente elemento. En bucles anidados, break 2; sale del bucle interior y del exterior.

Ilustración de los lenguajes de programación de Coddy

Aprende a programar con Coddy

COMENZAR