PHP 引用(&)意味著**多個變量名指向同一個 zval 容器**(內存地址),修改其中任一變量將影響所有引用者。本質是符號表中多個鍵指向同一 zval,引用計數 refcount > 1。
$a = "ABC";
$b = &$a; // $b 引用 $a
$b = "EFG";
echo $a; // EFG (全局變量被修改)
function inc(&$n) { $n++; }
$x = 1;
inc($x);
echo $x; // 2
function &getCounter() {
static $c = 0;
return $c;
}
$a = getCounter(); // 值傳遞,$a=0
$a = 5; // 不影響靜態變量
$b = &getCounter(); // 引用返回,$b 綁定靜態 $c
$b = 10; // 靜態 $c 變為 10
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 (不受影響)
$a = "long string"; $b = $a; → 符號表 $a、$b 指向同一 zval,refcount=2,is_ref=0。$a .= "x"; → Zend 檢測 refcount>1,複製 zval 內容到新內存,$a 指向新 zval,$b 保留舊值。unset($a):斷開符號表綁定,refcount--,歸零時釋放內存。xdebug_debug_zval('a') 可查看 zval 結構(需安裝 Xdebug)。& 避免複製(PHP 7+ 內部優化已大幅降低複製開銷,按需使用)。@return Type&。foreach ($arr as &$v),循環後 unset($v) 斷開引用防污染。$a = 1;
$b = &$a;
unset($a); // $b 仍為 1,內存未釋放(refcount=1)
echo $b; // 1
理解引用本質是符號表別名,而非 C 指針,能避開 99% 的 PHP 內存 Bug。