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 leforeach
afin qu'il contienne maintenant*** bb
que 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.