PHP 函數參數傳遞看似簡單,實則蘊含「值傳遞」、「引用傳遞」、「對象句柄傳遞」三種語義差異。理解它們對於編寫可預測、無副作用的代碼至關重要。本文通過代碼實驗逐一驗證行為差異。
<?php
function exam($var1) {
$var1++;
echo "In Exam: $var1<br/>";
}
$var1 = 1;
echo "$var1<br/>"; // 1
exam($var1); // In Exam: 2
echo "$var1<br/>"; // 1 ← 外部變量未改變
?>
結論:函數接收變量副本,內部修改不影響外部原變量。適用於純計算、不需回寫場景。
& 符號打通內外<?php
function exam(&$var1) {
$var1++;
echo "In Exam: $var1<br/>";
}
$var1 = 1;
echo "$var1<br/>"; // 1
exam($var1); // In Exam: 2
echo "$var1<br/>"; // 2 ← 外部變量同步修改
?>
結論:函數簽名加 &,實參與形參綁定同一記憶體地址,雙向同步。慎用:增加耦合、降低可讀性,僅在需明確修改外部變量時使用(如大數組去重、避免拷貝開銷)。
<?php
function values($price, $tax = 0) { // 建議給預設值而非空字串
$price += $price * $tax;
echo "Total Price: $price<br/>";
}
values(100, 0.25); // Total Price: 125
values(100); // Total Price: 100
?>
注意:原碼 $tax="" 導致字串參與運算隱式轉型為 0,雖結果相同但語意不清,建議直接 $tax = 0 或 $tax = null 配合 ?? 運算符。
<?php
class Obj {
public $name, $age, $gender;
public function __construct($name, $age, $gender) {
$this->name = $name; $this->age = $age; $this->gender = $gender;
}
public function show_info() {
echo "{$this->name} {$this->age} {$this->gender}<br/>";
}
}
function grow($obj) {
$obj->age++; // 修改對象屬性
}
$obj = new Obj("Mr. Zhan", 12, "male");
$obj->show_info(); // Mr. Zhan 12 male
grow($obj);
$obj->show_info(); // Mr. Zhan 13 male ← 外部對象被修改
grow($obj);
$obj->show_info(); // Mr. Zhan 14 male
?>
| 傳遞方式 | 函數簽名 | 內部修改參數變量本身 | 內部修改對象屬性/元素 |
|---|---|---|---|
| 值傳遞 (標量/陣列) | func($x) | 不影響外部 | 不影響外部 (陣列為副本) |
| 引用傳遞 | func(&$x) | 影響外部 | 影響外部 |
| 對象傳遞 | func($obj) | 不影響外部 (重新賦值 $obj=new Obj 只斷開局部綁定) | 影響外部 (句柄指向同一實例) |
& 即可修改對象狀態;若需在函數內替換整個對象實例並反映外部,才加 &。function grow(Obj $obj): void 靜態分析可捕獲誤用。掌握參數傳遞語義,是從「能跑通」進階到「寫得穩」的關鍵一步。下次定義函數時,請先問自己:這個參數,我希望函數內部能改變外部嗎?