Maitrise foreach en PHP avec notre guide complet. Exemples basiques et (très) avancés.
Le foreach est une instructions très utilisée en PHP. Dans cet article, on va passer en revue toutes ses possibilités et subtilités. Tu utilises foreach tous les jours avec tes tableaux PHP et tu penses le connaitre par coeur ? Je suis sûr qu’il y a au moins 1 fonctionnalité que tu vas découvrir dans cet article ! C’est parti !
Au programme :
Pour commencer simplement, on va considérer que foreach sert à parcourir les valeurs d’un tableau. Si tu n’es pas familier avec la notion de tableaux (ou array) en PHP, nous avons écrit un guide dédié aux tableaux en PHP. foreach s’utilise de cette façon :
$tableau = ['valeur 1', 'valeur 2', 'valeur 3'];
foreach ($tableau as $valeur) {
echo $valeur;
}
// Va afficher successivement : "valeur 1", "valeur 2", "valeur 3"
Voici ce qui se passe :
Quelques précisions supplémentaires :
Exemple avec le calcul d’une somme :
$tableauDeChiffres = [1, 2, 3, 4, 5];
$sommeDesDoubles = 0;
foreach ($tableauDeChiffres as $chiffre) {
$chiffre *= 2; // Je multiplie la valeur par 2
$sommeDesDoubles += $chiffre; // J'ajoute ce double à ma somme
}
echo $sommeDesDoubles; // Affiche 30 (2 + 4 + 6 + 8 + 10)
Un tableau associatif fonctionne avec un système de clé => valeur.
Lorsque je parcours un tableau avec un foreach, on a vu qu’on récupérait les valeurs. Mais on peut aussi récupérer les clés !
// Voici les informations d'un Avenger
$avenger = [
'prenom' => 'Tony',
'nom' => 'Stark',
'profession' => 'Gérant de Stark Industries'
];
// J'affiche ses informations sous forme de liste
echo '<ul>';
foreach ($avenger as $information => $valeur) {
echo '<li>' . ucfirst($information) . ' : ' . $valeur . '</li>';
}
echo '</ul>';
Voici ce qui se passe :
Quelques précisions supplémentaires :
Exemple avec le premier bout de code :
$tableau = ['valeur 1', 'valeur 2', 'valeur 3'];
foreach ($tableau as $key => $valeur) {
echo $key . ' => ' . $valeur;
}
// Va afficher successivement : "0 => valeur 1", "1 => valeur 2", "2 => valeur 3"
On a vu comment parcourir un tableau avec foreach, mais on peut aussi le faire avec un for, ou avec un while.
Pour commencer, il faudra compter le nombre d’éléments du tableau, puis forcément passer par les index du tableau. Ca ne va donc fonctionner globalement que pour les tableaux qui ont des index numériques consécutifs (autrement, on se trouverait face à un code techniquement possible mais alambiqué !).
Exemple :
$tableau = ['valeur 1', 'valeur 2', 'valeur 3'];
$nbElements = count($tableau); // 3 éléments dans mon tableau
// Mes éléments sont indexés de 0 à 2
for ($i = 0; $i < $nbElements; $i++) {
echo $i . ' => ' . $tableau[$i];
}
Quelques précisions :
Par contre, il y a un cas de figure où utiliser un for pour parcourir un tableau est intéressant… En fait ce n’est pas pour parcourir un tableau… mais plusieurs ! Exemple :
// Exemple issu du challenge COLLECTION_1 => https://tainix.fr/challenge/Collectionneur-de-figurines
$prix = [30, 15, 15, 30];
$cotes = [1, 1.2, 2, 3.5];
$nb = count($prix);
$somme = 0;
for ($i = 0; $i < $nb; $i++) {
$somme += $prix[$i] * $cotes[$i];
}
echo $somme;
Il est obligatoire que les 2 tableaux aient des index similaires, sinon on risque de déclencher des erreurs.
Là il va falloir feinter un peu, on va utiliser la fonction array_shift, native en PHP qui à la fois retourne le premier élément d’un tableau ET le retire du tableau en même temps.
Exemple :
$tableau = ['valeur 1', 'valeur 2', 'valeur 3'];
while ($valeur = array_shift($tableau)) {
echo $valeur;
}
Quelques précisions :
Maintenant, voyons voir comment parcourir un tableau avec un mélange de if, de match et de goto… nan je déconne, on va pas faire ça 😀
Imaginons que j’exécute ce code :
$tableauVide = [];
foreach ($tableauVide as $valeur) {
// Opérations très complexes sur $valeur
}
Que va t-il se passer ?
Eh bien il ne se passe rien ! Je n’ai pas besoin de contrôler que mon tableau n’est pas vide avant de faire un foreach. Comme le tableau est vide, aucune itération ne sera effectuée.
On avait déjà vu cela dans nos trucs et astuces en PHP (la 5ème va vous étonner 😉 )
Un peu de programmation orientée objet, je crée un objet et j’essaye de le parcourir avec un foreach. On va utiliser la promotion de propriétés dans le constructeur :
class Avenger {
public const CAMP = 'gentils';
public function __construct(
public readonly string $prenom,
public string $nom,
public string $profession,
protected string $motDePasse,
private int $puissance
) {}
public function metArmure(): void
{
}
}
$ironMan = new Avenger('Tony', 'Stark', 'Gérant de Stark Industries', 'PepperLove', 1000);
echo '<ul>';
foreach ($ironMan as $information => $valeur) {
echo '<li>' . ucfirst($information) . ' : ' . $valeur . '</li>';
}
echo '</ul>';
// Ce code affichera une liste avec le prénom, le nom et la profession
Quelques précisions :
Il y a des cas, parfois plus en phase de développements, où il peut être intéressant d’utiliser foreach sur un objet pour lister les valeurs de ses propriétés publiques.
On passe à foreach un tableau vide, pas d’erreur. On passe à foreach un objet, pas d’erreur.
Mais quelles sont les erreurs qu’on rencontre fréquemment avec un foreach ?
L’instruction break sert à interrompre une boucle, elle fonctionne pour un for, un while et donc aussi un foreach ! C’est utile par exemple quand on recherche une information dans un tableau ; une fois cette information trouvée, on peut arrêter de parcourir le tableau et retourner au programme principal :
// Tous les objets qui sont sur mon bureau au moment où j'écris cet article
$objets = ['téléphone', 'tasse vide', 'cahier', 'stylo', 'souris', 'figurine pop', 'magazine', 'clavier', 'tasse pleine'];
// Il y a du bazar...
$objetRecherche = 'stylo';
$objetTrouve = false; // Je ne l'ai pas encore trouvé
foreach ($objets as $objet) {
if ($objet === $objetRecherche) {
$objetTrouve = true;
break; // J'ai trouvé mon objet, je peux arrêter de chercher !
}
}
var_dump($objetTrouve); // bool(true)
break est aussi utile quand on travaille des tableaux volumineux, de plusieurs centaines ou milliers d’éléments. Quand les opérations nécessaires sont réalisées, plus besoin de parcourir le reste du tableau. Cela peut engendrer de véritables gains de performance !
Un autre exemple plus poussé : se passer des else en PHP grâce au break
L’instruction « copine » de break ! Cette fois-ci, continue sert à passer à l’itération suivante. J’aime bien voir ça comme un évitement de certaines données du tableau dans le cadre d’un traitement à effectuer. Exemple avec mes données précédentes :
// Tous les objets qui sont sur mon bureau au moment où j'écris cet article
$objets = ['téléphone', 'tasse vide', 'cahier', 'stylo', 'souris', 'figurine pop', 'magazine', 'clavier', 'tasse pleine'];
// Combien de tasse traine sur ce bureau ?
$nbTasses = 0;
foreach ($objets as $objet) {
if (! str_starts_with($objet, 'tasse')) {
continue;
}
$nbTasses++;
}
echo $nbTasses; // 2
Ca peut paraitre un peu bizarre, pourquoi ne pas mettre l’incrémentation directement dans le if, au lieu d’avoir ! + continue. J’aime bien procéder comme ça, pour éviter de mettre mes instructions principales dans un if. Le if me permet de contrôler les données de façon défensive. En codant de cette façon, il devient plus facile par exemple de rajouter un autre if, qui réaliserait un autre contrôle.
Un autre exemple plus poussé : se passer de else en PHP grâce au continue
Dans le bloc d’instructions d’un foreach, il est tout à fait possible de faire appel à un autre foreach :
$avengers = [
['nom' => 'Thor', 'pouvoir' => 'Super Marteau'],
['nom' => 'Captain America', 'pouvoir' => 'Super Bouclier'],
['nom' => 'Black Widow', 'pouvoir' => 'Super espionne'],
['nom' => 'Back Panther', 'pouvoir' => 'Super Costume'],
['nom' => 'Hulk', 'pouvoir' => 'Super rayons gamma'],
];
foreach ($avengers as $avenger) {
echo '<ul>';
foreach ($avenger as $information => $value) {
echo '<li>' . $information . ' : ' . $value . '</li>';
}
echo '</ul>';
}
Il est intéressant de noter ici que le deuxième foreach fait appel à $avenger, qui est la variable gérée dynamiquement par le premier foreach ! Ce n’est pas une obligation mais c’est tout à fait possible et fonctionnel, $avengers étant un tableau de tableaux.
En PHP, il est possible de « casser » plusieurs boucles d’un coup (break) ou de passer aux itérations suivantes à travers plusieurs boucles (continue).
Exemple avec break 2, je cherche les attaques nécessaires et suffisantes que doivent réaliser les avengers pour combattre un ennemi :
$avengers = [
['nom' => 'Thor', 'attaques' => [20, 20, 50]],
['nom' => 'Captain America', 'attaques' => [10, 20, 40]],
['nom' => 'Black Widow', 'attaques' => [10, 20, 30]],
['nom' => 'Back Panther', 'attaques' => [10, 20, 30]],
['nom' => 'Hulk', 'attaques' => [100, 100, 150]],
];
$forceTotaleAttaques = 0;
$forceEnnemi = 150;
$attaques = [];
foreach ($avengers as $avenger) {
foreach ($avenger['attaques'] as $forceAttaque) {
$attaques[] = $avenger['nom'] . ':' . $forceAttaque;
$forceTotaleAttaques += $forceAttaque;
if ($forceTotaleAttaques >= 150) {
break 2; // Je "casse" mes 2 foreach en même temps
}
}
}
echo $forceTotaleAttaques; // 160, je m'arrête dès que j'atteints ou dépasse 150
var_dump($attaques); // 'Thor:20' 'Thor:20' 'Thor:50' 'Captain America:10' 'Captain America:20' 'Captain America:40'
Et un exemple avec continue 2, je cherche à organiser des combats entre super vilain et super héros, sauf ceux qui ont un pouvoir vraiment trop puissant :
$superHeros = [
['nom' => 'Thor', 'pouvoir' => 'Super Marteau'],
['nom' => 'Captain America', 'pouvoir' => 'Super Bouclier'],
['nom' => 'Hulk', 'pouvoir' => 'Super rayons gamma'],
];
$superVilains = [
['nom' => 'Loki', 'pouvoir' => 'Manipulation'],
['nom' => 'Thanos', 'pouvoir' => 'Super force'],
['nom' => 'Abomination', 'pouvoir' => 'Super rayons gamma'],
];
foreach ($superHeros as $heros) {
foreach ($superVilains as $vilain) {
// Si l'un des deux a le pouvoir "Super rayons gamma", on passe à la prochaine itération
if ($heros['pouvoir'] === 'Super rayons gamma' || $vilain['pouvoir'] === 'Super rayons gamma') {
continue 2;
}
echo $heros['nom'] . " contre " . $vilain['nom'];
}
}
// Affiche : "Thor contre Loki" "Thor contre Thanos" "Captain America contre Loki" "Captain America contre Thanos"
Important : on peut très bien avoir un « break 3 », « continue 4 », etc., techniquement il n’y a pas de limite. Cependant, il est souvent déconseillé de trop imbriquer les boucles entre elles, au risque de créer des problématiques de performances liées à un nombre d’itérations beaucoup trop grand.
Quand on parcourt un tableau avec foreach, on peut vouloir modifier les valeurs d’un tableau, mais si on fait ça :
$nombres = [1, 2, 3];
foreach ($nombres as $nombre) {
$nombre++;
}
Que contient $nombres ?? On pourrait se dire que ça contient [2, 3, 4]… mais non ! En fait $nombres n’est pas modifié dans ce code. Chaque valeur contenues dans $nombres est passée successivement dans la nouvelle variable $nombre qui n’a donc pas de lien direct avec $nombres.
Alors comment faire pour changer les valeurs de $nombres ? On va voir 2 méthodes et une spécificité liée aux objets.
L’idée ici est de faire le calcul sur $nombre, puis d’utiliser l’index (obligatoire) pour venir mettre à jour $nombres :
$nombres = [1, 2, 3];
foreach ($nombres as $key => $nombre) {
$nombre++;
$nombres[$key] = $nombre;
}
Les quoi ? Les références en PHP permettent de créer un « alias » ou un autre nom pour une variable qui existe déjà. Autrement dit, une référence et une variable pointe vers la même valeur stockée en mémoire. Ce n’est pas comme une copie, c’est vraiment 2 éléments qui pointent au même endroit. Si on en change un, ça changera forcément la valeur pour les 2. On utilise le symbole & pour gérer les références. Exemple :
$a = &$b;
Toute modification apportée à $a ou $b affectera également l’autre variable. Les références vont être utiles dans les cas où l’on souhaite manipuler de grande structures de données comme des tableaux ou des objets, mais sans les copier.
Revenons à nos tableaux, on peut utiliser la notion de référence de cette façon :
foreach ($nombres as &$nombre) {
$nombre++;
}
Ici, le symbole & avant la variable $nombre va donc créer une référence à chaque élément du tableau $nombres au lieu d’en créer une copie. Quand on incrémente $nombre dans la boucle, on modifie donc directement les valeurs contenues dans $nombres. Et on retrouve bien [2, 3, 4] à la fin.
Important : il est fortement conseillé de supprimé la référence après le foreach pour éviter des erreurs + tard dans le code. Grâce à la fonction unset :
// Après le foreach
unset($nombre);
Prenons un objet assez basique qui a une méthode pour modifier une propriété. Je vais créer ensuite un tableau de plusieurs instances de cet objet :
class Avenger
{
public function __construct(
private string $name,
public int $force
) {}
public function addForce(int $add): void
{
$this->force += $add;
}
}
$avengers = [
new Avenger('Thor', 10),
new Avenger('Captain America', 10),
new Avenger('Black Widow', 10),
];
foreach ($avengers as $avenger) {
$avenger->addForce(5);
}
Ici, si je controle le contenu de $avengers, chaque Avenger aura bien 15 comme force. Et je n’ai pas eu besoin d’utiliser &. C’est parce que les objets fonctionnent de base par référence. Quand on fait $avenger = new Avenger(…), $avenger contient par défaut une référence à l’instance de la classe Avenger nouvellement créée.
C’est pour ça aussi qu’on a la fonction clone pour les objets, car si je fais :
$thor = new Avenger('Thor', 10);
$thor2 = $thor;
$thor2->addForce(5);
Comme $thor2 a en fait copié la référence à l’instance de la classe, si on debug $thor, on retrouvera bien 15 comme force aussi. Si ce n’est pas clair, n’hésite pas à creuser la notion de référence et de te renseigner sur la fonction clone 😉
Mais on n’a pas dit qu’on devait forcément passer un tableau ou un objet à foreach ??
Si ! Mais on peut aussi transformer une chaine de caractères en tableau au moment du foreach !
$alphabet = 'abcdefghijklmnopqrstuvwxyz';
foreach (str_split($alphabet) as $lettre) {
echo $lettre;
}
Dans cette astuce, on utilise donc la fonction str_split. Il est important de noter que str_split a un deuxième argument facultatif « length », par défaut à 1 pour régler la taille du découpage. Si on met une valeur différente de 1, ce ne sera donc plus un découpage caractère par caractère mais un découpage par groupe de caractères.
En fait, foreach accepte 3 types :
Un iterable est un objet qui implémente l’interface Iterator. Ca tombe bien, on a un article dédié sur le sujet. Tu pourras comprendre ce que propose cette interface et comment créer un objet Iterable en PHP.
PHPStan peut contrôler un ensemble d’éléments autour de l’utilisation du foreach :
Bonne nouvelle, environ 90% des challenges proposés par Tainix permettent de mettre en application le foreach. Comme il est question au début d’un challenge de récupérer un jeu de données, on va souvent commencer par parcourir ce jeu de données, et donc utiliser un foreach.
Petite sélection tout de même des challenges qui permettent de mettre en pratique foreach :
Et oui… tout ça pour ça ! Tout un magnifique guide pour maitriser foreach dans les moindres recoins pour finir sur l’alternative ultime à foreach : array_map.
En quelques mots, array_map permet d’appliquer une fonction sur tous les éléments d’un tableau. Pour découvrir array_map ou en connaitre toutes les subtilités, tu peux te diriger vers notre guide complet de array_map en PHP.
Autres contenus à découvrir
Corrigés, challenges, actualités, veille technique... aucun spam.