PHP 的參考(Reference)讓多個變數名稱指向同一份記憶體內容,類似 Unix 硬連結。這與 C 指標有本質差異。本文系統講解參考的建立、函數傳遞、回傳、物件行為,並釐清常見誤區。
參考是符號表別名:$a =& $b 表示 $a 與 $b 指向同一個 zval 容器。修改其中一個,另一個同步變化。
<?php
$a = 100;
$b = &$a; // $b 參考 $a
echo "$a, $b"; // 100, 100
$a++;
echo "$a, $b"; // 101, 101 -- 兩者同步變化
?>
在函數參數前加 &,呼叫端對應引數也必須是變數(不可為表達式),函數內修改將影響外部變數。
<?php
function addOne(&$num) {
$num++;
}
$val = 5;
addOne($val);
echo $val; // 6
?>
函數宣告與呼叫端雙雙加 &,回傳變數參考而非複製值。常用於鏈式操作或效能敏感場景。
<?php
class Counter {
private $value = 0;
public function &getValue() {
return $this->value;
}
}
$obj = new Counter();
$ref = &$obj->getValue(); // 取得參考
$ref = 10;
echo $obj->getValue(); // 10 -- 實際修改了物件屬性
?>
「物件預設傳遞是參考」是錯誤觀念。 PHP 5+ 物件變數存放的是「物件標識符」,傳遞時複製的是標識符(像傳值),但指向同一物件實體。真正的參考需顯式加 &。
<?php
class A { public $v = 1; }
$a = new A();
$b = $a; // 複製標識符,$a/$b 指向同一物件
$b->v = 2;
echo $a->v; // 2 -- 修改了同一物件
$c = new A();
$a = $c; // $a 現在指向新物件,$b 仍指向舊物件
$a->v = 3;
echo $b->v; // 2 -- $b 未受影響
// 真正參考物件變數
$d = new A();
$e = &$d; // $e 是 $d 的別名
$d = new A(); // $d 指向新物件,$e 也跟著指向新物件
?>
PHP 內核採用 COW 優化:$b = $a 時不複製記憶體,僅增加引用計數;當任一變數發生寫入操作,才真正分離複製。參考(&)則強制共享同一 zval,寫入直接影響所有別名。
unset($b) 僅銷毀別名 $b,不影響 $a 的內容(不同於 C 的 free(ptr) 會導致懸空指標)。
$ref = &$arr['key']foreach ($arr as &$v) 迴圈結束後建議 unset($v) 釋放參考,防止後續誤用