55 votes

Comportement étrange de foreach

<?php
  $a = array('a', 'b', 'c', 'd');

  foreach ($a as &$v) { }
  foreach ($a as $v) { }

  print_r($a);
?>

Je pense qu'il s'agit d'un programme normal mais c'est le résultat que j'obtiens :

Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => c
)

Quelqu'un peut-il m'expliquer cela ?

115voto

Mark Baker Points 90240

C'est un comportement bien documenté de PHP Voir le avertissement sur la page foreach de php.net

Avertissement

Référence d'un Valeur et le dernier élément du tableau restent même après que le foreach boucle. Il est recommandé de le détruire par unset().

$a = array('a', 'b', 'c', 'd');

foreach ($a as &$v) { }
unset($v);
foreach ($a as $v) { }

print_r($a);

EDITAR

Tentative de guide étape par étape de ce qui se passe réellement ici.

$a = array('a', 'b', 'c', 'd');
foreach ($a as &$v) { }   // 1st iteration $v is a reference to $a[0] ('a')
foreach ($a as &$v) { }   // 2nd iteration $v is a reference to $a[1] ('b')
foreach ($a as &$v) { }   // 3rd iteration $v is a reference to $a[2] ('c')
foreach ($a as &$v) { }   // 4th iteration $v is a reference to $a[3] ('d')

                          // At the end of the foreach loop,
                          //    $v is still a reference to $a[3] ('d')

foreach ($a as $v) { }    // 1st iteration $v (still a reference to $a[3]) 
                          //    is set to a value of $a[0] ('a').
                          //    Because it is a reference to $a[3], 
                          //    it sets $a[3] to 'a'.
foreach ($a as $v) { }    // 2nd iteration $v (still a reference to $a[3]) 
                          //    is set to a value of $a[1] ('b').
                          //    Because it is a reference to $a[3], 
                          //    it sets $a[3] to 'b'.
foreach ($a as $v) { }    // 3rd iteration $v (still a reference to $a[3]) 
                          //    is set to a value of $a[2] ('c').
                          //    Because it is a reference to $a[3], 
                          //    it sets $a[3] to 'c'.
foreach ($a as $v) { }    // 4th iteration $v (still a reference to $a[3]) 
                          //    is set to a value of $a[3] ('c' since 
                          //       the last iteration).
                          //    Because it is a reference to $a[3], 
                          //    it sets $a[3] to 'c'.

3voto

dimitis Points 31

La première foreach ne modifie pas le tableau, comme nous nous y attendions. Cependant, elle provoque $v pour se voir attribuer une référence à chacun des $a Les éléments de l'entreprise, de sorte que, lorsque la première boucle est terminée, $v est, en fait, une référence à $a[2] .

Dès que la deuxième boucle commence, $v se voit maintenant attribuer la valeur de chaque élément. Cependant, $v est déjà une référence à $a[2]; par conséquent, toute valeur qui lui est assignée sera copiée automatiquement dans le dernier élément du tableau !

Ainsi, lors de la première itération, $a[2] deviendra zéro, puis un, et enfin un à nouveau, étant effectivement copié sur lui-même. Pour résoudre ce problème, vous devez toujours annuler les variables que vous utilisez dans vos boucles foreach by-reference. ou, mieux encore, éviter complètement de les utiliser.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X