PHP 引用(&)讓不同變量名指向同一內容,類似 Unix 硬鏈接。本文系統講解變量引用、函數引用傳參、對象引用行為、取消引用、引用返回等核心機制,並辨析常見誤區。
<?php
$a = 100;
$b = &$a; // $b 引用 $a
echo $b; // 100
echo $a; // 100
$b = 200;
echo $a; // 200 ← 修改 $b 影響 $a
echo $b; // 200
?>
本質:$a 與 $b 指向同一個 zval 容器,修改任一者均影響另一者。
<?php
function main($a, &$b) {
$b = $a + 100;
return $b;
}
main(55, $b); // 實參前加 & 表示引用傳遞
echo $b; // 155
?>
注意:PHP 5.4+ 移除 了函數調用時的 & 寫法(main(55, &$b)),只能在函數定義處聲明 function main($a, &$b)。
<?php
class Club { public $name = "Real Madrid"; }
$b = new Club;
$c = $b; // 對象賦值默認即為引用行為(句柄拷貝)
echo $b->name; // Real Madrid
echo $c->name; // Real Madrid
$b->name = "Ronaldo";
echo $c->name; // Ronaldo ← 修改 $b 影響 $c
?>
關鍵點:PHP 5+ 對象變量存儲的是對象標識符(handle),而非對象本身。賦值、傳參、返回均複製標識符,指向同一對象實例。若需深拷貝請用 clone。
<?php
$a = 'Ronaldo';
$b = &$a;
unset($a); // 僅斷開 $a 與內容的綁定,$b 仍可訪問內容
?>
unset 只銷毀符號表條目,不銷毀內容(除非引用計數歸零)。
<?php
function foo(&$var) { $var++; }
$a = 5;
foo($a); // 合法:變量
foo(new stdClass()); // 合法:new 表達式(PHP 5.3+)
function bar() { $a = 5; return $a; }
foo(bar()); // 非法:函數返回值非變量(PHP 5.0.5+ 致命錯誤)
foo($a = 5); // 非法:表達式非變量
foo(5); // 非法:常量非變量
?>
<?php
function a(&$b) { $b++; }
$c = 0;
call_user_func_array('a', array(&$c)); // 參數數組中需加 &
echo $c; // 1
?>
<?php
function &test() {
static $b = 0;
$b++;
echo $b . "\n";
return $b;
}
$a = test(); // 輸出 1,普通調用,$a 得到值 1
$a = 5;
$a = test(); // 輸出 2,$a 得到值 2,靜態 $b 不變
$a = &test(); // 輸出 3,引用返回,$a 與靜態 $b 綁定
$a = 5; // 修改 $a 實為修改 $b
$a = test(); // 輸出 6,$b 已變為 5,遞增後為 6
?>
規則:$a = &test() 才是引用返回;$a = test() 僅獲取返回值。
<?php
$a = array('abe','ben','cam');
foreach ($a as $k => &$n) $n = strtoupper($n);
foreach ($a as $k => $n) echo "$n\n"; // 最後輸出 ABE BEN BEN
print_r($a); // [ABE, BEN, BEN]
?>
原因:第一個循環後 $n 仍引用 $a[2]。第二個循環每次將 $n 綁定到當前元素,但首次迭代時 $n(仍引用 $a[2])被賦值為 'ABE',導致 $a[2] 被改寫。解決:unset($n) 斷開引用。
$b = &$afunction(&$param)clonefunction &foo(),調用 $a = &foo()理解引用機制能避免難以排查的副作用 Bug,也是 PHP 進階開發必備內功。