Introducción: Por qué foreach no es solo "para cada"
Si llevas al menos una semana programando en PHP, ya habrás usado foreach cientos de veces. Es, probablemente, el bucle favorito de todo desarrollador: corto, elegante, sin contadores innecesarios. Pero ¿alguna vez te has preguntado qué sucede realmente bajo el capó cuando escribes foreach ($array as $value)?
La pregunta "How does PHP 'foreach' actually work?" ha acumulado miles de visitas en Stack Overflow. Y no es casualidad. El comportamiento de foreach esconde varias sorpresas, especialmente cuando se trata de referencias, bucles anidados y arrays no estándar.
En este tutorial no solo repasaremos la sintaxis. Nos adentraremos en el motor de PHP, entenderemos el puntero interno de arrays, veremos cómo funcionan los iteradores y aprenderemos a evitar trampas. ¡Allá vamos!
1. Anatomía de foreach: lo que dice la documentación
Empecemos por lo básico. foreach está diseñado para recorrer arrays y objetos. La sintaxis es simple:
<?php$fruits = ['apple', 'banana', 'cherry'];
foreach ($fruits as $fruit) { echo $fruit . "";}// Salida: apple banana cherry?>Pero también existe una segunda forma: con clave:
<?php$prices = ['apple' => 100, 'banana' => 50];
foreach ($prices as $name => $price) { echo "$name cuesta $price rublos.";}?>Parece todo obvio. Pero profundicemos. PHP procesa foreach de manera diferente a for o while. Internamente, utiliza el puntero interno de array (internal array pointer) y un mecanismo de iteración especial.
2. Puntero interno de array: el agente secreto
Cada array en PHP tiene un "cursor" invisible: el puntero interno. Apunta al elemento actual. Las funciones current(), next(), prev(), end() y reset() lo controlan.
Cuando ejecutas foreach, PHP hace lo siguiente:
- Reinicia el puntero interno al primer elemento (como
reset()). - En cada iteración, toma el elemento al que apunta el puntero.
- Desplaza el puntero al siguiente elemento (como
next()). - Repite hasta llegar al final.
Veamos esto en acción:
<?php$array = [10, 20, 30];
// Simulación manual de foreachreset($array); // Puntero al primer elementowhile ($value = current($array)) { echo $value . " "; next($array); // Desplazamos el puntero}// Salida: 10 20 30?>Pero hay un detalle: si el array está vacío o contiene false, este truco fallará. foreach funciona correctamente siempre porque utiliza un mecanismo interno más fiable: los iteradores.
3. Iteradores y foreach: el enfoque moderno
A partir de PHP 5, foreach puede trabajar no solo con arrays, sino también con cualquier objeto que implemente la interfaz Traversable (o su heredera Iterator).
Cuando pasas un objeto a foreach, PHP llama a los métodos del iterador:
rewind()— reinicio al iniciovalid()— verifica si hay un elementocurrent()— obtiene el valorkey()— obtiene la clavenext()— avanza al siguiente
Ejemplo de iterador personalizado:
<?phpclass NumbersIterator implements Iterator { private $position = 0; private $numbers = [1, 2, 3, 4, 5];
public function rewind() { $this->position = 0; }
public function current() { return $this->numbers[$this->position]; }
public function key() { return $this->position;