foreach en PHP – Le guide complet

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 :

Documentation du foreach en PHP

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 :

  • Mon tableau a ici 3 éléments, il y aura donc 3 itérations de ma boucle foreach. Si mon tableau a N éléments, il y aura N itérations. C’est à dire que la ou les instructions contenues entre les accolades { } seront répétées N fois.
  • A chaque itération, ce que contient $valeur change, pour prendre successivement la valeur de chaque élément du tableau, dans l’ordre du tableau.

Quelques précisions supplémentaires :

  • Ici j’affiche $valeur, mais j’aurais pu m’en servir pour faire des calculs, ou même altérer sa valeur. A chaque nouvelle itération, on repart de la valeur du prochain élément du tableau.
  • A l’intérieur des accolades de mon foreach, je peux accéder aux variables de mon programme principal. A l’inverse d’une fonction par exemple qui a son propre contexte.

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)

foreach avec un tableau associatif en PHP

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 :

  • A chaque itération, on a toujours $valeur qui prend chaque valeur du tableau. Mais en plus, $information prend la valeur de chaque clé correspondante. Dans les documentations classiques, ou dans les autocomplétions des éditeurs de code, on retrouve souvent : foreach ($array as $key => $value) { … }
  • Ce qui valait dans la section précédente vaut ici, on peut manipuler $information et $valeur comme on le souhaite.

Quelques précisions supplémentaires :

  • Cette structure aurait fonctionné avec un tableau « non associatif », comme dans la section précédente. En fait les tableaux peuvent être considérés comme toujours associatifs, car il y a toujours une clé. Mais si on ne la définit pas, PHP la définit tout seul, de façon numérique, en commençant par zéro et en incrémentant de 1 à chaque nouvel élément.

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"

foreach avec un tableau de tableaux en PHP

Possibilité moins connue en PHP, mais si tu dois parcourir un tableau de tableaux, tu peux attribuer plusieurs variables en même temps dans la déclaration du foreach.

Prenons quelques Avengers :

$avengers = [
    ['Tony', 'Armure high tech'],
    ['Spiderman', 'Toiles d\araignée'],
    ['Thor', 'Marteau divin']
];

On va pouvoir récupérer chaque valeur dans plusieurs variables de la façon suivante :

foreach ($avengers as [$nom, $pouvoir]) {
    echo "L'avenger $nom a le pouvoir : $pouvoir";
}

// Au lieu de faire :
// foreach ($avengers as $avenger) {
//     $nom = $avenger[0];
//     $pouvoir = $avenger[1];
//     echo "L'avenger $nom a le pouvoir : $pouvoir";
// }

Attention, ça n’aurait pas fonctionner avec ce tableau :

$avengers = [
    ['name' => 'Tony', 'power' => 'Armure high tech'],
    ['name' => 'Spiderman', 'power' => 'Toiles d\araignée'],
    ['name' => 'Thor', 'power' => 'Marteau divin']
];

foreach ou for ou while, le combat des boucles en PHP

On a vu comment parcourir un tableau avec foreach, mais on peut aussi le faire avec un for, ou avec un while.

Parcourir un tableau avec un for

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 :

  • Il est important de faire le count avant le for et non dans sa déclaration, sinon celui-ci est répété à chaque itération.
  • Il est important de bien gérer les conditions dans le for, ici on démarre à 0 et on est strictement inférieur à $nbElements. Si je mets « <= » je déclenche une erreur car l’élément indexé à 3 n’existe pas.
  • On n’a plus $valeur, mais on fait appel à $tableau directement
  • Je considère que ces 3 points ne jouent pas du tout en faveur du for pour parcourir les éléments d’un tableau. Le foreach est beaucoup plus pratique et beaucoup plus lisible. Le fait de pouvoir donner un nom spécifique pour les valeurs est très intéressant pour la lisibilité du code.

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.

Parcourir un tableau avec un while

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 :

  • J’ai retrouvé $valeur, on pourrait considérer que c’est un bon point.
  • A chaque fois que la condition de mon while est vérifié, je récupère une valeur de mon tableau qui est retirée du tableau. Ce qui veut dire qu’à la fin, je fais array_shift([]) (tableau vide) et là array_shift renvoie false, ce qui a pour effet de sortir de mon while.
  • A moins de passer par une variable gérée manuellement, je ne peux pas récupérer les clés de mon tableau.
  • A moins d’être dans un cas précis où j’ai besoin de vider mon tableau au fur et à mesure (on pourrait dire « consommer les valeurs du tableau »), cette syntaxe n’est pas recommandée pour parcourir un tableau.

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 😀

foreach sur un tableau vide en PHP

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 😉 )

foreach sur un objet en PHP

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 :

  • L’ensemble des propriétés publiques seront accessibles et affichées ici.
  • On retrouve donc le nom de la propriété en lieu et place de la clé
  • Les propriétés protected et private ne sont pas accessibles depuis le foreach
  • la spécificité « readonly » n’a pas d’impact. C’est « public » qui rend accessible la propriété dans le foreach
  • Les constantes ou méthodes ne sont pas accessibles depuis le foreach
  • Si la classe hérite d’une autre classe et que cette classe parente a des propriétés publiques, elles seront accessibles (en premières, avant les propriétés de la classe courante)
  • Si la classe utilise un trait et que ce trait a des propriétés publiques, elles seront accessibles (en dernières, après les propriétés de la classe courante)

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.

Les erreurs possibles avec foreach en PHP

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 ?

  • Le tableau passé à foreach peut être vide, mais si foreach reçoit null alors il déclenchera une erreur.
  • De la même façon, si on passe à foreach un int, un float, un bool, une string il déclenchera une erreur.

foreach et break en PHP

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

foreach et continue en PHP

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

Imbriquer les foreach en PHP

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.

Impacts sur break et continue

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.

Modifier les valeurs d’un tableau avec foreach en PHP

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.

Sans référence, avec les index

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;
}

Avec les références

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);

Cas particulier des objets

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 😉

Parcourir une chaine de caractères avec un foreach en PHP

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.

C’est quoi un iterable en PHP ?

En fait, foreach accepte 3 types :

  • Les tableaux
  • Les objets
  • Les iterables

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.

foreach et l’analyse statique avec PHPStan

PHPStan peut contrôler un ensemble d’éléments autour de l’utilisation du foreach :

  • Vérification des variables utilisées dans le foreach : un tableau ? un objet ? un iterable ?
  • Détection d’indices inexistants. Si on parcourt un tableau et qu’on cherche à accéder à un index qui en fait n’existe pas.
  • Avertissement si on modifie l’itérateur ($valeur dans foreach($tableau as $valeur)). Il est en effet déconseillé de changer sa valeur pour éviter des erreurs ou des comportements inattendus.
  • Avertissement si une référence créée dans un foreach n’est pas supprimé après la boucle (cf. un peu + haut sur l’utilisation des références dans un foreach)

On met en pratique avec des exercices PHP autour 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 :

Se passer des foreach grâce à array_map en PHP

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.


Qui a codé ce superbe contenu ?

Keep learning

Autres contenus à découvrir


Ta newsletter chaque mois

Corrigés, challenges, actualités, veille technique... aucun spam.