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

PHP 引用 (&) 深度解析:變量、函數、對象與性能陷阱

     編輯:PHP 綜合知識

引用本質:符號表別名

PHP 引用(&)使兩個變量名指向同一個 zval 容器(內存中的值容器)。不同於 C 指針存儲地址,PHP 引用是符號表層面的別名綁定。核心機制是寫時複製 (Copy-on-Write, COW):讀取時共享內存,寫入時才複製。

1. 變量引用

$a = "ABC";
$b = &$a;  // $b 成為 $a 的別名
$b = "EFG";
echo $a; // EFG (兩者同步)

unset($a) 僅刪除符號表條目,不銷毀值容器($b 仍可訪問)。

2. 函數引用傳參

function add100(&$n) { $n += 100; }
$val = 1;
add100($val); // 調用時不加 &
echo $val; // 101

// 錯誤:add100(1); // 傳值表達式無法引用
// call_user_func_array 特例:需傳引用
call_user_func_array('add100', [&$val]);

3. 函數引用返回

function &getStatic() {
    static $counter = 0;
    return $counter++;
}

$r1 = getStatic();   // 0 (值拷貝)
$r2 = &getStatic();  // 1 (引用綁定)
$r2 = 99;
echo getStatic();    // 100 (靜態變量被修改)

規則:$r = &func() 才建立引用綁定,$r = func() 為值拷貝。

4. 對象引用 (PHP 5+)

class A { public $v = 1; }
$o1 = new A();
$o2 = $o1;     // PHP 5+ 默認對象賦值即引用行為
$o2->v = 2;
echo $o1->v; // 2

// 深拷貝需用 clone
$o3 = clone $o1;
$o3->v = 3;
echo $o1->v; // 2 (不受影響)

PHP 4 時代對象賦值為拷貝,需 &new 顯式引用。PHP 5+ new 自動返回引用,&new 已棄用 (E_STRICT)。

5. 全局引用與 $GLOBALS

$g = 'global';
function test($useGlobals) {
    global $g; // 等價 $g = &$GLOBALS['g'];
    if ($useGlobals) {
        $GLOBALS['g'] = 'changed via GLOBALS'; // 影響全局
    } else {
        $g = 'changed local'; // 僅影響局部綁定
    }
}

6. $this 引用

對象方法內 $this 永遠是調用對象的引用,不可重新綁定。

性能陷阱:錯誤使用引用導致提前複製

$bigArray = range(1, 100000);

// 情況 A:值傳遞 (COW 生效,無複製)
function readOnly($arr) { return count($arr); }
readOnly($bigArray); // 內存不增

// 情況 B:引用傳遞 (Zend 引擎預判可能寫入,強制複製)
function refParam(&$arr) { return count($arr); }
refParam($bigArray); // 內存瞬間翻倍!

// 情況 C:無引用聲明但函數內修改參數
function modify($arr) { $arr[0] = 0; } // 參數無 &,但內部寫入
modify($bigArray); // 發生 COW 複製,內存翻倍

結論:除非確需修改原變量,不要濫用引用傳參。大數組/字符串傳遞時,值傳遞配合 COW 反而更高效。

最佳實踐清單

場景建議理由
函數需修改外部變量引用傳參 func(&$var)語義明確,避免返回值賦值
大數組只讀遍歷值傳遞 func($arr)利用 COW 共享內存
對象方法鏈式調用返回 $this對象本身即引用行為
foreach 修改原數組元素foreach ($arr as &$v)循環後建議 unset($v) 解除引用
緩存變量手動釋放$var = null引用計數歸零觸發 GC

經典面試題:輸出什麼?

$a = 1;
$b = &$a;
$c = $b;
$c = 2;
echo $a; // 2 ($b 引用 $a,$c 賦值時拷貝值,但 $c=2 時 $c 斷開引用?實測:$c=$b 是值拷貝,$c=2 不影響 $a 輸出 1)
// 正確分析:$b=&$a 綁定,$c=$b 值拷貝(1),$c=2 僅改 $c,$a 仍為 1
echo $a; // 1
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved