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

PHP 參考陷阱:一行 & 導致 count() 效能暴跌 4 倍

     編輯:PHP 綜合知識

在高頻呼叫的函式中,無心插入的參考賦值 $timequeue = &$arr['timequeue'] 導致處理 22 MB 資料從 10 秒飆升至 40 秒。根因在於 參考標記改變了 zval 類型,破壞了 Copy-on-Write,迫使 count() 每次都複製整個陣列。

問題程式碼

function update_timelist(&$arr, $timestamp, $threshold) {
    $timequeue = &$arr['timequeue']; // 問題在這一行
    while (!empty($timequeue[0]) && ($timestamp - $timequeue[0]) > $threshold) {
        array_shift($timequeue);
    }
    array_push($timequeue, $timestamp);
    if ($arr['count'] < count($timequeue)) { // count() 變慢
        $arr['count'] = count($timequeue);
    }
}

優化後(移除參考)

function update_timelist(&$arr, $timestamp, $threshold) {
    while (!empty($arr['timequeue'][0]) && ($timestamp - $arr['timequeue'][0]) > $threshold) {
        array_shift($arr['timequeue']);
    }
    array_push($arr['timequeue'], $timestamp);
    if ($arr['count'] < count($arr['timequeue'])) {
        $arr['count'] = count($arr['timequeue']);
    }
}

執行時間從 40 秒降至 10 秒。

核心原理圖解

  1. 無參考時:$arr['timequeue'] 為非參考 zval(is_ref=0)。count() 讀取時觸發 COW,但因無寫入,不複製,僅增加 refcount,極快。
  2. 加上 & 後:$timequeue 標記為 is_ref=1。PHP 規定同一 zval 不能同時為參考與非參考,故必須立即複製一份給原陣列元素,$timequeue 持有新副本(參考),原陣列持有舊副本(非參考)。
  3. count($timequeue) 時:count 內部要求非參考 zval,發現參數是參考類型,再次複製整個陣列以滿足非參考需求。每次循環都複製 → O(n²) 災難。

關鍵認知

  • array_shift、array_push 等陣列函式參數本身就是參考傳遞(函式簽名為 array_shift(array &$array)),直接傳 $arr['timequeue'] 即可修改原陣列,不需要額外加 &。
  • 參考的主要用途:函式需修改呼叫端變數本身(如交換變數、重新指派陣列)。單純修改陣列元素不需參考。
  • 除錯技巧:xdebug_debug_zval('var') 可查看 refcount、is_ref 狀態。

最佳實踐清單

  1. 函式參數預設不加 &,除非確定需修改變數綁定。
  2. 操作陣列元素時,直接用 $arr['key'],勿建立中介參考變數。
  3. 高頻循環中避免 count()、sizeof() 重複呼叫,預存長度或用 for 迴圈。
  4. 使用 PHP 7.4+ WeakReference 或物件識別符替代強參考,減少複製壓力。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved