PHP 變數底層儲存的是「指向值的地址」,而非值本身。理解這一點,才能徹底搞懂值傳遞、引用傳遞(&)、物件複製與複製行為的本質區別。
$a = 1; // 實際過程: // 1. 解析器在記憶體分配空間存放整數 1 // 2. 將該記憶體地址存入變數 $a 的符號表條目 // 3. 讀取 $a 時:查符號表 → 取地址 → 讀記憶體值 → 輸出
&):共享同一記憶體地址$a = 1; $b = &$a; // $b 存入 $a 的地址,非複製值 echo $b; // 1 $a = 2; echo $b; // 2 ← 改變 $a,$b 同步變化 $b = 3; echo $a; // 3 ← 雙向綁定
結論:$a 與 $b 指向同一記憶體位址,是同一個變數的不同別名。
$a = 1; $b = $a; // 複製 $a 的地址,但 PHP 採用 COW 機制 $a = 2; echo $b; // 1 ← $b 仍指向舊值 1
標量(整數、浮點、字串、布林)、陣列在賦值時觸發 Copy-on-Write:實際複製發生在「任一變數被修改」時刻,而非賦值瞬間。
class User { public $name = 'Tom'; }
$a = new User;
$b = $a; // 未用 &,但物件標識符被複製
$a->name = 'Jim';
echo $b->name; // Jim ← 兩變數指向同一物件實例
關鍵區別:物件變數存的是「物件標識符」,賦值複製的是標識符,故指向同一實例。若需獨立副本,必須用 clone:
$b = clone $a; // 建立新實例,屬性淺拷貝 $a->name = 'Tom'; echo $b->name; // Jim
| 宣告 | 呼叫 | 行為 |
|---|---|---|
function f($x) | f($a) | 值傳遞(標量/陣列 COW,物件共享實例) |
function f(&$x) | f($a) | 引用傳遞,函數內修改影響外部變數 |
function f(User $x) | f($a) | 型別宣告,仍屬值傳遞(複製物件標識符) |
foreach ($arr as &$v) { $v *= 2; }
unset($v); // 必須 unset,否則 $v 仍引用最後一個元素
function &f() { return $globalVar; } 僅在需「修改返回值」時使用(如鏈式賦值),濫用降低可讀性ArrayObject/Generatorclone 或 readonly 屬性(PHP 8.1+)| 類型 | 賦值 $b=$a | 引用 $b=&$a | 函數傳值 | 函數傳引用 |
|---|---|---|---|---|
| 標量/字串 | COW 獨立 | 共享 | COW | 共享 |
| 陣列 | COW 獨立 | 共享 | COW | 共享 |
| 物件 | 共享實例 | 共享變數槽 | 共享實例 | 共享變數槽 |
| 資源 | 共享資源 ID | 共享變數槽 | 共享資源 ID | 共享變數槽 |
掌握「地址、COW、物件標識符」三大核心概念,即可精準預測 PHP 變數在任何情境下的行為。