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

PHP 變量引用機制全圖解:符號表、寫時複製與對象引用

     編輯:PHP 相關知識

從底層原理理解 & 引用

PHP 引用(&)意味著**多個變量名指向同一個 zval 容器**(內存地址),修改其中任一變量將影響所有引用者。本質是符號表中多個鍵指向同一 zval,引用計數 refcount > 1。

三種引用類型

1. 變量引用

$a = "ABC";
$b = &$a;   // $b 引用 $a
$b = "EFG";
echo $a;    // EFG  (全局變量被修改)

2. 函數傳址調用

function inc(&$n) { $n++; }
$x = 1;
inc($x);
echo $x;    // 2

3. 函數引用返回

function &getCounter() {
    static $c = 0;
    return $c;
}
$a = getCounter();   // 值傳遞,$a=0
$a = 5;              // 不影響靜態變量
$b = &getCounter();  // 引用返回,$b 綁定靜態 $c
$b = 10;             // 靜態 $c 變為 10

對象引用特殊性(PHP 5+)

class Foo { public $v = 'A'; }
$o1 = new Foo();
$o2 = $o1;        // PHP 5+ 對象賦值默認即引用行為(句柄複製)
$o2->v = 'B';
echo $o1->v;      // B

// 深拷貝需用 clone
$o3 = clone $o1;
$o3->v = 'C';
echo $o1->v;      // B (不受影響)

Zend 引擎「寫時複製」 (Copy-on-Write)

  1. $a = "long string"; $b = $a; → 符號表 $a、$b 指向同一 zval,refcount=2,is_ref=0。
  2. 修改 $a .= "x"; → Zend 檢測 refcount>1,複製 zval 內容到新內存,$a 指向新 zval,$b 保留舊值。
  3. 此機制對**標量、數組**生效;**對象**默認傳遞句柄(類似引用),不觸發 COW。

引用計數與垃圾回收

  • unset($a):斷開符號表綁定,refcount--,歸零時釋放內存。
  • 循環引用(對象互相引用)需 GC 算法回收(PHP 5.3+)。
  • xdebug_debug_zval('a') 可查看 zval 結構(需安裝 Xdebug)。

最佳實踐

  1. **傳遞大數組/字符串**時使用 & 避免複製(PHP 7+ 內部優化已大幅降低複製開銷,按需使用)。
  2. **函數返回引用**僅用於靜態變量/單例等特定場景,文檔標註 @return Type&。
  3. **foreach 循環修改原數組**需 foreach ($arr as &$v),循環後 unset($v) 斷開引用防污染。
  4. **對象無需 &**:PHP 5+ 対象賦值、傳參、返回天然為句柄引用行為。

經典面試陷阱

$a = 1;
$b = &$a;
unset($a);   // $b 仍為 1,內存未釋放(refcount=1)
echo $b;     // 1

理解引用本質是符號表別名,而非 C 指針,能避開 99% 的 PHP 內存 Bug。

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