首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP foreach 循環中的 Copy-On-Write 行為差異:值傳遞 vs 參考傳遞實測

     編輯:PHP 綜合知識

實測場景

陣列含 3 個長字串,分別測試三種 foreach 寫法的內存增量。

案例 1:值傳遞、唯讀

$m1 = memory_get_usage();
$arr = explode("\n", str_repeat("aaaaaaaaaaaaaa\n", 3));
foreach ($arr as $v) { $count++; } // 唯讀
$m2 = memory_get_usage();
echo $m2 - $m1; // 788 bytes(極小,無複製)

案例 2:值傳遞、寫入

$m1 = memory_get_usage();
$arr = explode("\n", str_repeat("aaaaaaaaaaaaaa\n", 3));
foreach ($arr as $v) {
    $count++;
    $v = 'aaaaaaaaaaaaaa'; // 寫入操作
}
$m2 = memory_get_usage();
echo $m2 - $m1; // 840 bytes(增長 ~52 bytes,觸發分離)

案例 3:參考傳遞、唯讀/寫入

$m1 = memory_get_usage();
$arr = explode("\n", str_repeat("aaaaaaaaaaaaaa\n", 3));
foreach ($arr as &$v) { // & 參考
    $count++;
    // $v = '...'; // 即使寫入也無增量
}
$m2 = memory_get_usage();
echo $m2 - $m1; // 788 bytes(與唯讀值傳遞相同)

核心結論

寫法唯讀寫入說明
as $v共享內存觸發 COW 分離預設行為,寫入時才複製
as &$v共享內存直接修改原陣列無分離,但修改影響原陣列

原理解析

  • as $v:每次迴圈將陣列元素 zval 的 refcount++,迴圈結束 refcount--。寫入時引擎檢測 refcount>1 執行分離。
  • as &$v:直接綁定元素 zval,is_ref=1,無分離機制,修改即時生效於原陣列。

效能與安全建議

  1. 唯讀遍歷大陣列:直接用 as $v,享受 COW 零複製優勢。
  2. 需修改原陣列元素:用 as &$v 避免分離開銷,但迴圈結束後 必須 unset($v) 解除參考,否則後續誤用 $v 會污染最後一個元素。
  3. 需修改但不影響原陣列:用 as $v 寫入(觸發分離)或迴圈前 $arr = $arr; 強制複製。
  4. PHP 7.0+ 對大字串/陣列複製優化極大,分離開銷通常可接受。

經典陷阱:參考殘留

$arr = [1,2,3];
foreach ($arr as &$v) { $v *= 2; }
unset($v); // 關鍵!
foreach ($arr as $v) { echo $v; } // 正常輸出 2 4 6
// 若無 unset($v),第二個迴圈 $v 仍參考 $arr[2],賦值會修改原陣列

總結

理解 foreach 中 COW 的觸發條件,能在處理大數據時做出正確選擇:唯讀用值傳遞、修改原陣列用參考並 unset、修改副本用值傳遞寫入。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved