前陣子公司定期技術研討會時,有人提出了一個問題。
$arr = [1, 2, 3]; foreach ($arr as &$a) {} foreach ($arr as $a) {} var_dump($arr);
考慮以上程式碼執行結果,試問陣列 $arr
在執行結束後的值會是如何?
註:執行環境 PHP 7.1 without swoole
結果:$arr
的值為 [1, 2, 2]
緣由
在 PHP 中,foreach
結束後,迴圈中的索引值(index)及內容(value)並不會被消滅。
$a = [1, 2, 3]; foreach ($a as $v) {} var_dump($v); // int(3) foreach ($a as $k => $value) {} var_dump($k, $value); // int(2), int(3)
同理,foreach ($a as &$v) {}
時,在迴圈結束後 $v
值不會被消滅,其值仍是參考於(referenced by)陣列中的最後一個值,執行範例如下:
$a = [1, 2, 3]; foreach ($a as &$v) {} var_dump($a); /* array(3) { [0]=> int(1) [1]=> int(2) [2]=> &int(3) } */
如果在迴圈結束後變更 $v
值,則陣列中的最後一個值也會一併被變更。
解決方法
在使用 foreach ($a as &$v) {}
這類寫法後,應手動 unset($v)
以避免潛在問題發生。
$a = [1, 2, 3]; foreach ($a as &$v) { // do something... } unset($v);
http://php.net/manual/en/control-structures.foreach.php
为了能够直接修改循环中的数组元素,在$ value之前 加上&。在这种情况下,该值将通过引用分配 。
<?php $arr = array(1, 2, 3, 4); foreach ($arr as &$value) { $value = $value * 2; } // $arr is now array(2, 4, 6, 8) unset($value); // break the reference with the last element ?>
警告
即使在foreach循环之后,$ value和最后一个数组元素的 引用仍然存在。建议通过unset()销毁它。否则您将遇到以下行为:
<?php $arr = array(1, 2, 3, 4); foreach ($arr as &$value) { $value = $value * 2; } // $arr is now array(2, 4, 6, 8) // without an unset($value), $value is still a reference to the last item: $arr[3] foreach ($arr as $key => $value) { // $arr[3] will be updated with each value from $arr... echo "{$key} => {$value} "; print_r($arr); } // ...until ultimately the second-to-last value is copied onto the last value // output: // 0 => 2 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 2 ) // 1 => 4 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 4 ) // 2 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 ) // 3 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 ) ?>