首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 參數傳遞深度解析:傳值 vs 傳址的差異、效能與最佳實務

     編輯:PHP 綜合知識

PHP 函式參數預設採用「傳值」,但可透過 `&` 符號改為「傳址」。兩者在記憶體行為、效能表現、適用場景上有顯著差異。本文以圖解與實測代碼,徹底釐清兩者機制,助你寫出更高效、可預期的程式碼。

核心差異一覽表

特性傳值傳址
語法`function foo($x)``function foo(&$x)`
記憶體行為複製變數值(Copy-on-Write 機制下未修改時共享)直接操作原變數記憶體位址
函式內修改影響外部否是
適用資料型態標量、陣列、物件(物件本身為 handle,傳值仍可修改內部屬性)需修改呼叫端變數本身(如交換變數、累加器)
效能(大型陣列/字串)PHP 7+ COW 機制下極佳,未寫入不複製略快於強制複製,但增加耦合風險

程式碼實證

傳值:外部變數不受影響

function byValue($val) {
    $val = 'changed inside';
    return $val;
}

$original = 'original';
echo byValue($original); // changed inside
echo $original;          // original(未變)

傳址:外部變數同步變更

function byRef(&$val) {
    $val = 'changed inside';
    return $val;
}

$original = 'original';
echo byRef($original); // changed inside
echo $original;        // changed inside(已被修改)

實務案例:交換兩個變數

function swap(&$a, &$b) {
    $tmp = $a;
    $a = $b;
    $b = $tmp;
}

$x = 1; $y = 2;
swap($x, $y);
echo "$x, $y"; // 2, 1

物件的特殊行為:傳值仍可修改內部狀態

PHP 物件變數實質是「物件識別碼」,傳值時複製的是識別碼,指向同一物件實體:

class User { public $name; }
function rename(User $u) { $u->name = 'New Name'; }

$user = new User();
$user->name = 'Old';
rename($user);
echo $user->name; // New Name(物件內部屬性被修改)

但若在函式內將參數「重新指派」為新物件,傳值不會影響外部,傳址則會:

function replace(User $u) { $u = new User(); $u->name = 'Replaced'; }
function replaceRef(User &$u) { $u = new User(); $u->name = 'ReplacedRef'; }

$u1 = new User(); $u1->name = 'A';
replace($u1);
echo $u1->name; // A(外部仍指向原物件)

$u2 = new User(); $u2->name = 'B';
replaceRef($u2);
echo $u2->name; // ReplacedRef(外部指向被換掉)

效能迷思與 PHP 7+ Copy-on-Write (COW)

許多開發者誤以為「大型陣列傳值會複製記憶體導致效能差」。實際上 PHP 7 引入 COW 機制:

  • 傳值時僅增加 zval 參考計數,不複製底層資料。
  • 只有當函式內「寫入」該參數時,才會觸發複製。
  • 因此唯讀傳遞大型陣列/字串,傳值效能等同傳址,且語意更清晰、副作用更少。
$big = range(1, 1_000_000); // 約 8MB 陣列
function readOnly($arr) { return count($arr); } // 唯讀
function modify($arr) { $arr[0] = 999; }        // 寫入觸發複製

// readOnly($big)  幾乎零開銷
// modify($big)    會複製 8MB 記憶體

最佳實務建議

  1. 預設使用傳值:語意明確、無副作用、配合 COW 效能無虞。
  2. 僅在必要時用傳址:
    • 需修改呼叫端變數本身(交換、累加、工廠函式回傳新物件)
    • 極少數效能熱點經 Profiling 證實需避免複製(極罕見)
  3. 避免混用:同一函式簽名不可同時有傳值與傳址參數(PHP 8.1+ 已棄用部分配置)。
  4. 文件化副作用:若函式使用傳址,務必在 PHPDoc 標註 `@param type $param [in/out]` 或說明會修改外部變數。

掌握傳值/傳址機制,不只是面試題,更是寫出穩健、可維護 PHP 程式碼的關鍵基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved