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

PHP 引用機制深度解析:符號表別名、傳遞、返回與寫時拷貝

     編輯:PHP 相關知識

PHP 引用(&)讓多個變量名指向同一內容,類似 Unix 硬鏈接。本文系統講解引用的本質、賦值/傳遞/返回三大操作、unset 行為、foreach 陷阱、全局引用、對象引用,以及底層「寫時拷貝」機制。

引用的本質:符號表別名

$a =& $b;

$a 和 $b 完全等價,指向同一內存區域。不是 $a 指向 $b(C 指針風格)。

引用的三大用途

1. 引用賦值

$a = 5; $b =& $a; $b = 10; echo $a; // 10

2. 引用傳遞(函數參數)

function foo(&$var) { $var++; }
$a = 5; foo($a); echo $a; // 6
// 僅函數定義需 &,調用時不加(PHP 5.4+ 調用加 & 會警告)

可引用傳遞:變量、new 實例、函數引用返回。不可:表達式、字面量、非引用返回的函數調用。

3. 引用返回

class Foo { public $value = 42; public function &getValue() { return $this->value; } }
$obj = new Foo;
$myVal = &$obj->getValue(); // $myVal 引用 $obj->value
$obj->value = 2; echo $myVal; // 2
// 必須:聲明 &function、返回變量、調用處 &賦值,三處皆需 &

返回表達式(如 return ($this->value))會觸發 E_NOTICE 並失效。

特殊場景與陷阱

unset 引用:只斷開綁定,不銷毀內容

$a = 1; $b =& $a; unset($a); // $b 仍為 1,內容未銷毀

foreach 中的引用副作用

$ref = 0; $row =& $ref;
foreach (array(1,2,3) as $row) { /* ... */ }
echo $ref; // 3(最後一個元素值),因 $row 是引用,循環修改了 $ref

建議:foreach ($arr as $k => &$v) 結束後 unset($v) 斷開引用。

global 引用本質

global $var; // 等價於 $var =& $GLOBALS['var'];
function test($useGlobal) {
    global $var1, $var2;
    if (!$useGlobal) $var2 =& $var1; // 僅函數內可見
    else $GLOBALS['var2'] =& $var1; // 全局可見
}

對象與 $this

  • PHP 5+ 對象默認「句柄傳遞」(類似引用),$obj2 = $obj1 共享同一實例。
  • $obj2 =& $obj1 則是真正引用,unset($obj1) 不影響 $obj2,但 $obj1 = null 會導致 $obj2 也為 null(引用計數歸零)。
  • 方法中 $this 永遠是調用對象的引用。

底層機制:寫時拷貝 (Copy-on-Write)

$a = "ABC"; $b = $a; // 此時 $a、$b 指向同一內存
$a = "EFG";      // 發生寫操作,Zend 為 $b 複製一份 "ABC",重新申請內存
  • 讀操作共享內存,寫操作才分離。
  • 大數組/對象傳參時,若無修改,不產生拷貝開銷;若需修改,建議顯式 function(&$arr) 避免隱式拷貝。

最佳實踐建議

  • 大數組傳參、需修改原值 → 使用引用 function(&$arr)。
  • 對象傳參默認共享實例,通常無需加 &。
  • 手動清理大對象:$obj = null(引用計數歸零觸發 GC),而非 unset($obj)(僅斷開變量名)。
  • 避免濫用引用,增加代碼認知負擔;PHP 7+ 內存管理優化,大多數場景值傳遞性能足夠。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved