2010-07-22 69 views
159

參考我有這樣的代碼:PHP通行證通過的foreach

$a = array ('zero','one','two', 'three'); 

foreach ($a as &$v) { 

} 

foreach ($a as $v) { 
    echo $v.PHP_EOL; 
} 

有人可以解釋爲什麼輸出是: 零一個二兩。

來自zend認證學習指南。

+50

'unset($ your_used_reference);'每次使用'foreach($ var as&$ your_used_reference)''! – Wrikken 2010-07-22 09:39:49

+3

感謝您的意見,但我只是想了解第二個foreach如何工作的邏輯。 – Centurion 2010-07-22 12:07:19

+9

爲什麼$ your_used_reference(或OP中的$ v)不會自動取消設置?它的範圍是foreach,不應該超越? – Hurix 2014-01-17 15:54:16

回答

127

因爲在第二個循環中,$v仍然是對最後一個數組項的引用,所以它每次都被覆蓋。

你可以看到它這樣的:

$a = array ('zero','one','two', 'three'); 

foreach ($a as &$v) { 

} 

foreach ($a as $v) { 
    echo $v.'-'.$a[3].PHP_EOL; 
} 

正如你所看到的,最後一個數組項以當前循環值:「零」,「一」,「二」,然後它只是'兩個'...)

+1

好吧,這意味着在最後一次迭代中最後一項還是保持兩次,或者再次分配兩次,爲什麼不是三次爲什麼在最後一次停止? :) – Centurion 2010-07-22 14:40:31

+4

它不停止。最後一個數組項目分配有當前循環值。所以它被分配爲「零」,然後是「一個」,然後是「兩個」。在最後一次迭代中,由於之前的迭代,它被賦予了它自己的值,即'2'。所以它只是保持'兩'。 – Macmade 2010-07-22 14:46:11

+8

提高輸出後,我能夠理解: '$ v獲得項[0](零)。 $ a [3]現在爲零 $ v獲得項目[1](一)。 $ a [3]現在是一個 $ v獲得項[2](兩個)。 $ a [3]現在是兩個 $ v獲得項目[3](兩個)。 $ a [3]現在是兩個' – Eduardo 2013-09-02 02:18:40

0

因爲如果你創建一個變量的引用,那個變量的所有名字(包括原始的)成爲引用。

+0

如果是這種情況,那麼爲什麼如果在第二個循環中將$ v更改爲&$ v,它是否會改變結果,即它會迴應零個,一個,兩個,三個? – 2010-07-22 09:43:27

+0

,因爲當您在第二個循環中使用&$ v時,您正在更改變量的引用。因此,問題被消除了。 – dejavu 2010-07-22 09:59:39

133

我不得不花幾個小時來弄清楚爲什麼每次迭代都會改變[3]。這是我到達的解釋。

PHP中有兩種類型的變量:正常變量和引用變量。如果我們將一個變量的引用賦值給另一個變量,該變量就成爲一個引用變量。

例如在

$a = array('zero', 'one', 'two', 'three'); 

如果我們做

$v = &$a[0] 

第0個元素($a[0])成爲基準變量。 $v指向該變量;因此,如果我們對$v進行任何更改,它將反映在$a[0]中,反之亦然。

如果我們現在做

$v = &$a[1] 

$a[1]將成爲一個參考變量,$a[0]將成爲一個正常的變量(因爲沒有其他人指向$a[0]將它轉換成一個正常的變量。PHP是足夠聰明到使其在沒有其他人朝它指向一個正常的變量)

這是在第一循環

foreach ($a as &$v) { 

} 
會發生什麼

最後一次迭代後$a[3]是一個參考變量。

由於$v指向$a[3]$v導致變化的任何變化,以在第二回路$a[3]

foreach ($a as $v) { 
    echo $v.'-'.$a[3].PHP_EOL; 
} 
在每次迭代

$v變化,$a[3]變化。 (因爲$v仍然指向$a[3])。這就是爲什麼$a[3]在每次迭代時都會發生變化的原因。

在最後一次迭代之前的迭代中,$v被賦值爲'2'。由於$v指向$a[3],$a[3]現在得到值'2'。記住這一點。

在上一次迭代中,$v(指向$a[3])現在的值爲'2',因爲$a[3]在前一次迭代中被設置爲2。打印出two。這解釋了在上次迭代中打印$ v時爲什麼會重複「two」。

+19

感謝您的詳細解釋 – Vodaldrien 2013-05-22 12:45:53

+2

我愛你的解釋,但這仍然是讓我不斷困惑的事情之一。我必須記住要安撫理智的人。 :-) – liamvictor 2015-07-14 10:37:49

+0

很好解釋。謝謝! – phpnerd 2017-03-22 04:42:25

1

我發現這個例子也很棘手。爲什麼在最後一次迭代的第二次循環中沒有任何事情發生($ v保持'兩'),是$ v指向$ a [3](反之亦然),所以它不能賦值給自己,所以它保持以前分配的值:)

41

第一循環

$v = $a[0]; 
$v = $a[1]; 
$v = $a[2]; 
$v = $a[3]; 

是的!目前$v = $a[3]的位置。

第二環路

$a[3] = $v = $a[0], echo $v; // same as $a[3] and $a[0] == 'zero' 
$a[3] = $v = $a[1], echo $v; // same as $a[3] and $a[1] == 'one' 
$a[3] = $v = $a[2], echo $v; // same as $a[3] and $a[2] == 'two' 
$a[3] = $v = $a[3], echo $v; // same as $a[3] and $a[3] == 'two' 

因爲$a[3]由前處理分配。

+5

在閱讀本文之前,無法理解其他答案的含義。謝謝! – thanksd 2015-12-16 22:21:35

+0

我也是:) tks !! – MarceloBoni 2017-01-21 02:48:58

3

此:

$a = array ('zero','one','two', 'three'); 

foreach ($a as &$v) { 

} 

foreach ($a as $v) { 
    echo $v.PHP_EOL; 
} 

相同

$a = array ('zero','one','two', 'three'); 

$v = &$a[3]; 

for ($i = 0; $i < 4; $i++) { 
    $v = $a[$i]; 
    echo $v.PHP_EOL; 
} 

OR

$a = array ('zero','one','two', 'three'); 

for ($i = 0; $i < 4; $i++) { 
    $a[3] = $a[$i]; 
    echo $a[3].PHP_EOL; 
} 

OR

$a = array ('zero','one','two', 'three'); 

$a[3] = $a[0]; 
echo $a[3].PHP_EOL; 

$a[3] = $a[1]; 
echo $a[3].PHP_EOL; 

$a[3] = $a[2]; 
echo $a[3].PHP_EOL; 

$a[3] = $a[3]; 
echo $a[3].PHP_EOL; 
12

我覺得這段代碼更清楚地顯示了程序。

<?php 

$a = array ('zero','one','two', 'three'); 

foreach ($a as &$v) { 
} 

var_dump($a); 

foreach ($a as $v) { 
    var_dump($a); 
} 

結果: (以最後兩個陣列上的注意)

array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(5) "three" 
} 
array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(4) "zero" 
} 
array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(3) "one" 
} 
array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(3) "two" 
} 
array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(3) "two" 
} 
11

我來到這裏只是偶然和OP的問題了我的注意。不幸的是,我不明白上面的任何解釋。對我來說似乎每個人都知道,得到它,接受它,就是無法解釋。

幸運的是,從PHP文檔純句子上foreach使這完全清楚:

警告:$value參考和最後一個數組元素甚至foreach循環後依然存在。建議通過unset()銷燬它。

7

這個問題有很多解釋提供,但沒有明確的例子說明如何解決這個問題。在大多數情況下,您可能需要通過引用foreach傳遞以下代碼。

foreach ($array as &$row) { 
    // Do stuff 
    // Unset 
    unset($row); 
} 
+0

正確的做法。 – VSG24 2017-09-17 09:59:19

+0

沒有爲我工作,不得不使用通常的'unset($ row [$ k]);'而不是。 – Boykodev 2018-01-22 15:57:04