En route vers PHP 5.5 : foreach() et list(...) comme valeurs

15 octobre 2012php, php-5.5
 Cet article a été rédigé il y a plusieurs années et peut ne plus être tout à fait à jour…

Avec la version actuelle de la branche master de PHP (et donc, probablement, PHP 5.5), il est désormais possible, lorsque l’on boucle avec la syntaxe foreach() sur un tableau dont les éléments sont eux-même des tableaux, de ne plus obtenir l’élément (le sous-tableau) en lui-même, mais les sous-éléments le constituant, en utilisant la construction list() dans la partie valeur du foreach.

Cette nouvelle écriture est particulièrement adaptée à des situations où la structure de chaque ligne du tableau est connue à l’avance – typiquement, lorsqu’il s’agit de boucler sur un jeu de résultats obtenu depuis une base de données.

Utiliser list() en valeur d’un foreach

Par exemple, si on considère l’extrait de code suivant :

<?php
$arr = array(
    array('aaa', 'bbb'), 
    array(123, 456), 
);

foreach ($arr as list ($a, $b))
{
    var_dump($a, $b);
}

Et qu’on l’exécute avec une version récente de la branche master de PHP, nous obtiendrons comme sortie :

string(3) "aaa"
string(3) "bbb"
int(123)
int(456)

Avec PHP <= 5.4, pour obtenir le même résultat, nous aurions du procéder en deux étapes, sans utiliser directement l’instruction list() dans le foreach :

<?php
$arr = array(
    array('aaa', 'bbb'), 
    array(123, 456), 
);

foreach ($arr as $ligne)
{
    list ($a, $b) = $ligne;
    var_dump($a, $b);
}

La différence n’est certes pas révolutionnaire : il ne s’agit finalement que d’un peu de sucre syntaxique.

Et avec un foreach $key => $value ?

Bien entendu, cette nouvelle syntaxe fonctionne aussi si nous souhaitons utiliser la clef de chaque ligne :

<?php
$arr = [
    'premier' => ['aaa', 'bbb'], 
    'second' => [123, 456], 
];

foreach ($arr as $key => list ($a, $b))
{
    echo "$key => $a, $b\n";
}

Exécuter cet exemple nous donnerait comme sortie :

premier => aaa, bbb
second => 123, 456

Attention aux notices !

Par contre, cette écriture n’est pas adaptée au cas où le nombre de sous-éléments de chaque élément de votre liste ne serait pas le même ou serait inconnu.

En effet, si nous considérons cet extrait de code :

<?php
$arr = [
    'premier' => ['aaa', 'bbb'],    // Deux éléments
    'second' => [123],              // /!\ Un seul élément
];

foreach ($arr as $key => list ($a, $b))
{
    // pas d'utilisation des variables, pour éviter
    // d'introduire une notice dans le corps de la boucle
}

Exécuter cette portion de code ménerait à une notice :

PHP Notice:  Undefined offset: 1 
    in /.../php-5.5/tests/foreach-list/foreach-list-3.php on line 7

En effet, lors de la seconde itération, l’élément [123] est un tableau qui n’est lui-même constitué que d’un seul élément ; PHP ne peut donc renseigner $b et le signale.

Notez qu’il n’est pas possible d’utiliser l’opérateur @ pour masquer cette notice.
(Et vu les votes, quasiment tous négatifs, sur ce point précis de la RFC, il est peu probable que cela le devienne.)

Voir aussi