亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

PHP‘foreach’實際上是如何工作的?

PHP‘foreach’實際上是如何工作的?

PHP
滄海一幻覺 2019-06-01 14:44:41
PHP‘foreach’實際上是如何工作的?讓我在這之前說我知道foreach是,做,以及如何使用它。這個問題涉及到它在帽子下是如何工作的,我不想要任何類似于“這就是如何循環數組”這樣的回答。foreach".很長一段時間我以為foreach處理數組本身。然后,我發現許多引用都提到了這樣一個事實,即它與復制我認為這就是故事的結尾。但我最近就這件事進行了一次討論,經過一些實驗后,我發現這并不是100%的事實。讓我展示一下我的意思。對于以下測試用例,我們將使用以下數組:$array = array(1, 2, 3, 4, 5);測試用例1:foreach ($array as $item) {   echo "$item\n";   $array[] = $item;}print_r($array);/* Output in loop:    1 2 3 4 5    $array after loop: 1 2 3 4 5 1 2 3 4 5 */這清楚地表明,我們沒有直接使用源數組,否則循環將永遠繼續,因為我們在循環期間不斷地將項推到數組上。但為了確定情況是這樣的:測試用例2:foreach ($array as $key => $item) {   $array[$key + 1] = $item + 2;   echo "$item\n";}print_r($array);/* Output in loop:    1 2 3 4 5    $array after loop: 1 3 4 5 6 7 */這將支持我們的初步結論,我們正在循環期間處理源數組的副本,否則我們將在循環期間看到修改過的值。但是.。如果我們看看手冊,我們認為:當foreach第一次開始執行時,內部數組指針將自動重置到數組的第一個元素。好吧.。這似乎表明foreach依賴于源數組的數組指針。但我們剛剛證明不使用源數組對吧?不完全是。測試用例3:// Move the array pointer on one to make sure it doesn't affect the loopvar_dump(each($array));foreach ($array as $item) {   echo "$item\n";}var_dump(each($array));/* Output   array(4) {     [1]=>     int(1)     ["value"]=>     int(1)     [0]=>     int(0)     ["key"]=>     int(0)   }   1   2   3   4   5   bool(false) */因此,盡管我們沒有直接處理源數組,但是我們直接使用源數組指針-指針在循環結束時位于數組末尾這一事實表明了這一點。但這不可能是真的-如果是的話測試用例1會永遠循環。PHP手冊還指出:由于foreach依賴于內部數組指針,因此在循環中更改它可能會導致意外行為。那么,讓我們找出“意外行為”是什么(從技術上講,任何行為都是意外的,因為我已經不知道該期待什么了)。測試用例4:foreach ($array as $key => $item) {   echo "$item\n";   each($array);}/* Output: 1 2 3 4 5 */測試用例5:foreach ($array as $key => $item) {   echo "$item\n";   reset($array);}/* Output: 1 2 3 4 5 */.沒有什么出乎意料的,事實上,它似乎支持“來源的副本”理論.問題這里發生什么事情?我的C-fu不夠好,我不能僅僅通過查看PHP源代碼就能得出一個正確的結論,如果有人能幫我把它翻譯成英語,我會很感激的。在我看來foreach與復制,但將源數組的數組指針設置為循環后數組的末尾。整個故事都是這樣的嗎?如果沒有,它到底在做什么?是否存在使用函數調整數組指針的情況(each(), reset()等人)在foreach會影響循環的結果嗎?
查看完整描述

4 回答

?
嚕嚕噠

TA貢獻1784條經驗 獲得超7個贊

在示例3中,不修改數組。在所有其他示例中,您可以修改內容或內部數組指針。當涉及到PHP數組,因為賦值運算符的語義。

PHP中數組的賦值操作符更像是一個懶惰的克隆。將一個變量分配給另一個包含數組的變量將克隆該數組,這與大多數語言不同。然而,除非需要實際的克隆,否則不會進行實際的克隆。這意味著只有當任何一個變量被修改(在寫上復制)時,克隆才會發生。

以下是一個例子:

$a = array(1,2,3);$b = $a;  // This is lazy cloning of $a. For the time
          // being $a and $b point to the same internal
          // data structure.$a[] = 3; // Here $a changes, which triggers the actual
          // cloning. From now on, $a and $b are two
          // different data structures. The same would
          // happen if there were a change in $b.

回到您的測試用例,您可以很容易地想象foreach創建具有數組引用的某種迭代器。此引用與變量完全相同。$b以我為例。但是,迭代器和引用只在循環期間存在,然后,它們都被丟棄?,F在您可以看到,在除3之外的所有情況下,數組都是在循環期間修改的,而這個額外的引用是活動的。這觸發了一個克隆人,這就解釋了這里發生了什么!

這里有一篇關于這種抄寫行為的另一種副作用的優秀文章:PHP三元操作符:快還是慢?


查看完整回答
反對 回復 2019-06-01
?
FFIVE

TA貢獻1797條經驗 獲得超6個贊

使用時應注意的幾點foreach():

a)foreach前景拷貝原始數組的。意思是foreach()將具有共享數據存儲,直到或除非prospected copy未創建Exach Notes/用戶評論.

(B)觸發前景拷貝?策略的基礎上創建了一個前景副本。copy-on-write,也就是說,每當數組傳遞給foreach()更改后,將創建原始數組的克隆。

(C)原始數組和foreach()迭代器DISTINCT SENTINEL VARIABLES,即,一個用于原始數組,另一個用于foreach見下面的測試代碼。SPL , 迭代器,和陣列迭代器.

堆棧溢出問題如何確保在PHP中的“foreach”循環中重置值?回答你問題的案例(3,4,5)。

下面的示例顯示,每個()和Reset()不影響SENTINEL變量(for example, the current index variable).的.foreach()迭代器。

$array = array(1, 2, 3, 4, 5);list($key2, $val2) = each($array);echo "each() Original (outside): $key2 => $val2<br/>";
foreach($array as $key => $val){
    echo "foreach: $key => $val<br/>";

    list($key2,$val2) = each($array);
    echo "each() Original(inside): $key2 => $val2<br/>";

    echo "--------Iteration--------<br/>";
    if ($key == 3){
        echo "Resetting original array pointer<br/>";
        reset($array);
    }}list($key2, $val2) = each($array);echo "each() Original (outside): $key2 => $val2<br/>";

產出:

each() Original (outside): 0 => 1

foreach: 0 => 1

each() Original(inside): 1 => 2

--------Iteration--------

foreach: 1 => 2

each() Original(inside): 2 => 3

--------Iteration--------

foreach: 2 => 3

each() Original(inside): 3 => 4

--------Iteration--------

foreach: 3 => 4

each() Original(inside): 4 => 5

--------Iteration--------

Resetting original array pointer

foreach: 4 => 5

each() Original(inside): 0=>1

--------Iteration--------

each() Original (outside): 1 => 2


查看完整回答
反對 回復 2019-06-01
  • 4 回答
  • 0 關注
  • 506 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號