Dziwne zachowanie foreach

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

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

  print_r($a);
?>

Myślę, że to normalny program, ale to jest wyjście, które otrzymuję:

Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => c
)
Czy ktoś może mi to wyjaśnić?
Author: neworld, 2011-02-11

2 answers

Jest to dobrze udokumentowane zachowanie PHP Zobacz Ostrzeżenie na stronie foreach php.net

Warning

Odniesienie do $ value i ostatni element tablicy pozostaje nawet po pętli foreach. Zaleca się zniszczenie go przez unset ().

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

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

print_r($a);

EDIT

Spróbuj zrobić krok po kroku przewodnik po tym, co naprawdę się tutaj dzieje

$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'.
 77
Author: Mark Baker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-11 13:14:22

Pierwszy pętla foreach nie wprowadza żadnych zmian w tablicy, tak jak byśmy tego oczekiwali. Jednak powoduje to, że $v przypisane jest odniesienie do każdego z elementów $a, tak więc, do czasu zakończenia pierwszej pętli, $v jest w rzeczywistości odniesieniem do $a[2].

Jak tylko rozpocznie się druga pętla, $v jest teraz przypisana wartość każdej element. Jednak $v jest już odniesieniem do $a[2]; dlatego każda wartość przypisany do niego zostanie automatycznie skopiowany do ostatniego elementu macierz!

Tak więc, podczas pierwszej iteracji, $a[2] stanie się zerem, potem jedynką, a następnie kolejny, skutecznie kopiowany na siebie. Aby rozwiązać ten problem, ty należy zawsze wyłączyć zmienne, których używasz w swoim by-reference foreach pętle-albo, jeszcze lepiej, unikać korzystania z pierwszego całkowicie.

 3
Author: dimitis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-03 10:06:44