Introduction : Pourquoi foreach n'est pas simplement « pour chaque »
Si vous écrivez en PHP depuis au moins une semaine, vous avez déjà utilisé foreach des centaines de fois. C'est sans doute la boucle préférée de chaque développeur : courte, élégante, sans compteurs superflus. Mais vous êtes-vous déjà demandé ce qui se passe réellement sous le capot lorsque vous écrivez foreach ($array as $value) ?
La question « How does PHP 'foreach' actually work? » a recueilli des milliers de vues sur Stack Overflow. Et ce n'est pas un hasard. Le comportement de foreach cache plusieurs surprises, surtout lorsqu'il s'agit de références, de boucles imbriquées et de tableaux non standard.
Dans ce tutoriel, nous ne nous contenterons pas de répéter la syntaxe. Nous allons jeter un coup d'œil à l'intérieur du moteur PHP, comprendre le pointeur interne de tableau, voir comment fonctionnent les itérateurs, et apprendre à éviter les pièges. C'est parti !
1. Anatomie de foreach : ce que dit la documentation
Commençons par les bases. foreach est conçu pour parcourir les tableaux et les objets. La syntaxe est simple :
<?php$fruits = ['apple', 'banana', 'cherry'];
foreach ($fruits as $fruit) { echo $fruit . "";}// Affichage : apple banana cherry?>Mais il existe aussi une deuxième forme — avec la clé :
<?php$prices = ['apple' => 100, 'banana' => 50];
foreach ($prices as $name => $price) { echo "$name coûte $price roubles.";}?>Tout semble évident. Mais creusons un peu plus. PHP traite foreach différemment de for ou while. En interne, il utilise le pointeur interne de tableau (internal array pointer) et un mécanisme d'itération spécial.
2. Le pointeur interne de tableau : l'agent secret
Chaque tableau en PHP possède un « curseur » invisible — le pointeur interne. Il indique l'élément courant. Les fonctions current(), next(), prev(), end() et reset() le contrôlent.
Lorsque vous lancez foreach, PHP fait ceci :
- Réinitialise le pointeur interne sur le premier élément (comme
reset()). - À chaque itération, prend l'élément pointé par le pointeur.
- Décale le pointeur sur l'élément suivant (comme
next()). - Répète jusqu'à atteindre la fin.
Voyons cela en action :
<?php$array = [10, 20, 30];
// Imitation manuelle de foreachreset($array); // Pointeur sur le premier élémentwhile ($value = current($array)) { echo $value . " "; next($array); // Décale le pointeur}// Affichage : 10 20 30?>Mais il y a un détail : si le tableau est vide ou contient false, cette astuce échoue. foreach fonctionne toujours correctement car il utilise un mécanisme interne plus fiable — les itérateurs.
3. Itérateurs et foreach : l'approche moderne
Depuis PHP 5, foreach peut fonctionner non seulement avec les tableaux, mais aussi avec tout objet implémentant l'interface Traversable (ou son héritier Iterator).
Lorsque vous passez un objet à foreach, PHP appelle les méthodes de l'itérateur :
rewind()— réinitialisation au débutvalid()— vérification de l'existence d'un élémentcurrent()— obtenir la valeurkey()— obtenir la clénext()— passer au suivant
Exemple d'itérateur personnalisé :
<?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;