它就像一個人有兩個不同的名字。
在 PHP 中,引用是一種用不同名稱存取相同變數內容的方式。它們不像 C 語言的指標;例如,你不能使用它們執行指標運算,它們不是實際的記憶體位址等等。更多資訊請參見引用不是什麼。相反地,它們是符號表的別名。請注意,在 PHP 中,變數名稱和變數內容是不同的,因此相同的內容可以有不同的名稱。最接近的比喻是 Unix 的檔案名稱和檔案——變數名稱是目錄項目,而變數內容是檔案本身。引用可以比作 Unix 檔案系統中的硬連結。
與 C 語言不同,PHP 引用不被視為預先解引用的指標,而是完整的別名。
它們所建立別名(「引用」)的資料,直到所有對它的引用都被移除之前,都不會被垃圾回收機制回收。
「一般」變數本身也被視為引用,在垃圾回收的目的上,它們與使用 =& 賦值的變數沒有區別。
以下範例提供說明。
1) 當被視為包含值的變數時,引用的行為與預期一致。然而,它們實際上是*引用*原始資料的物件。
<?php
$var = "foo";
$ref1 =& $var; // 建立一個引用 $var 的新物件
$ref2 =& $ref1; // 直接引用 $var,而不是 $ref1!!!!!
echo $ref; // >foo
unset($ref);
echo $ref1; // >注意:未定義的變數:ref1
echo $ref2; // >foo
echo $var; // >foo
?>
2) 當透過引用存取時,原始資料在*所有*對它的引用都被移除之前不會被移除。這包括引用和沒有使用 & 運算子賦值的「一般」變數,並且在垃圾回收的目的上,兩者之間沒有區別。
<?php
$var = "foo";
$ref =& $var;
unset($var);
echo $var; // >注意:未定義的變數:var
echo $ref; // >foo
?>
3) 若要移除原始資料而不移除所有對它的引用,只需將其設為 null 即可。
<?php
$var = "foo";
$ref =& $var;
$ref = NULL;
echo $var; // 值為 NULL,所以不會印出任何東西
echo $ref; // 值為 NULL,所以不會印出任何東西
?>
4) 將資料放入陣列中也算作增加一個參考,就垃圾回收而言。
更多資訊,請參閱 https://php.dev.org.tw/manual/en/features.gc.refcounting-basics.php
以下三個程式碼片段顯示了在不同情況下,在純量變數、陣列和物件中使用參考的影響。
在任何情況下,如果您堅持參考是變數的別名的概念,結果都是預期的。透過參考賦值後(無論是 $a =& $b 還是 $b =& $a),兩個變數名稱都指向同一個變數。
純量變數的參考
<?php
/*
參考是同一個變數的別名
*/
$a = 1;
$b =& $a;
$b = 2;
echo "$a,$b\n"; // 2,2
$a = 3;
echo "$a,$b\n"; // 3,3
// 變數可以在賦值之前繫結
$c =& $d;
$c = 4;
echo "$c,$d\n"; // 4,4
?>
陣列的參考
<?php
/*
Array elements referencing scalar variables
*/
$a = 1;
$b = 2;
$c = array(&$a, &$b);
$a = 3;
$b = 4;
echo "c: $c[0],$c[1]\n"; // 3,4
$c[0] = 5;
$c[1] = 6;
echo "a,b: $a,$b\n"; // 5,6
/*
Reference between arrays
*/
$d = array(1,2);
$e =& $d;
$d[0] = 3;
$d[1] = 4;
echo "e: $e[0],$e[1]\n"; // 3,4
$e[0] = 5;
$e[1] = 6;
echo "d: $d[0],$d[1]\n"; // 5,6
$e = 7;
echo "d: $d\n"; // 7 ( $d is no more an array, but an integer )
/*
Iterating an array of references using foreach construct
*/
$a = 1;
$b = 2;
$f = array(&$a,&$b);
foreach($f as $x) // If $x is assigned by value it doesn't change referred variables.
$x = 3;
echo "a,b: $a,$b\n"; // 1,2
foreach($f as &$x) // If $x is assigned by reference it changes referred variables.
$x = 3;
echo "a,b: $a,$b\n"; // 3,3
// Be aware that, after the loop, $x still references $f[1] and so $b
$x = 4;
echo "a,b: $a,$b\n"; // 3,4 ( $b affected )
// To avoid previous side effects it is advisable to unset x, unlinking it from $f[1] and $b
unset($x);
$x = 5;
echo "a,b: $a,$b\n"; // 3,4 ( $b not affected )
?>
物件的參考
<?php
/*
物件屬性參考純量變數
*/
$a = 1;
$b = new stdClass();
$b->x =& $a;
$a = 2;
echo "b->x: $b->x\n"; // 2
$b->x = 3;
echo "a: $a\n"; // 3
/* 物件之間的參考 */
$c = new stdClass();
$c->x = 1;
$d =& $c;
$d->x = 2;
echo "c->x: $c->x\n"; // 2
$d = new stdClass();
$d->y = 3;
echo "c->y: $c->y\n"; // 3
echo "c->x: $c->x\n"; // 未定義的屬性:stdClass::$x
?>