Si le programme PHP ci-dessous est stocké dans bug.php, alors cette commande
<?php
$A = array
(
"aa",
"bb",
);
echo "Initial array\n";
print_r($A);
foreach ($A as $j => $line)
{
echo "j = $j line = $line\n";
echo "element $j is {$A[$j]}\n\n";
if ($j == 0)
$A[1] = "***" . $A[1];
}
echo "Final array\n";
print_r($A);
?>
produira cette sortie lors de l'utilisation de PHP 7.0.33-0ubuntu0.16.04.1 (cli) ( NTS) Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies avec Zend OPcache v7.0.33-0ubuntu0.16.04.1, Copyright (c) 1999-2017, par Zend Technologies
Sortie:
Initial array
Array
(
[0] => aa
[1] => bb
)
j = 0 line = aa
element 0 is aa
j = 1 line = bb <----------------------------------------------
element 1 is ***bb <----------------------------------------------
Final array
Array
(
[0] => aa
[1] => ***bb
)
Notez le lignes marquées ci-dessus. L'élément $ A [1] est "*** bb", mais $ line - que le foreach devrait associer à la clé 1 - est "bb".
S'agit-il d'un bogue, ou y a-t-il une subtilité PHP dont je ne suis pas conscient?
php bug.php
3 Réponses :
Sauf si le tableau est référencé, foreach () code > opère sur une copie du tableau spécifié et non sur le tableau lui-même. foreach a des effets secondaires sur le pointeur de tableau. Ne vous fiez pas au pointeur de tableau pendant ou après le foreach sans le réinitialiser.
Ainsi, lorsque vous modifiez $ A [1] , vous modifiez le tableau original , pas la copie que le foreach () utilise ensuite la boucle.
Cette distinction importante semble actuellement absente de la documentation officielle a >, mais vous pouvez en savoir plus ici: Comment fonctionne réellement PHP «foreach»?
Comme mentionné dans les notes sur php.net, à moins que le tableau ne soit référencé, foreach fonctionne sur une copie du tableau spécifié et non sur le tableau lui-même. Vous sortez une variable à partir de la copie d'origine, puis du tableau modifié.
Le tableau est transmis au foreach en tant que copie - sauf si vous le transmettez comme référence (indiquez-le en ajoutant un & à $ value ) cela ne reflétera pas les mises à jour de la valeur que vous effectuez dans la première itération.
Considérez ceci: p>
foreach ($A as $j => &$line)
{
echo "j = $j line = $line\n";
echo "element $j is {$A[$j]}\n\n";
if ($j == 0)
$A[1] = "***" . $A[1];
}
/* Will output:
* j = 0 line = aa
* element 0 is aa
*
* j = 1 line = ***bb
* element 1 is ***bb
*/
Vous voyez la & line qui signifie que nous passons dans le bloc une référence et maintenant tout changement est reflété dans le tableau et non dans un $ line copie du tableau initial que vous avez passé dans le bloc de boucle.
J'espère avoir été clair ...
J'ai remarqué que la documentation le dit exactement: p >
Cela dit exactement dans la documentation :) p>
Afin de pouvoir modifier directement les éléments du tableau dans la boucle, faites précéder $ value de &. Dans ce cas, la valeur sera attribuée par référence.
Vous avez modifié
$ A [1]lors du premier passage dans leforeachafin qu'il contienne maintenant*** bbque vous affichez ensuite le deuxième passage via leforeach. Cela semble tout à fait correct d'où je suis assis.Quel est votre résultat attendu, il n'est pas clair.
@Dave Je ne pense pas que vous compreniez pleinement la question et l'exemple.