在構造函數中建立引用可能會導致混淆的結果。本節以教學形式說明避免問題。
<?phpclass Foo { function Foo($name) { // 在全局陣列 $globalref 中建立一個引用 global $globalref; $globalref[] = &$this; // 將名字設定為傳遞的值 $this->setName($name); // 並輸出之 $this->echoName(); } function echoName() { echo "<br />",$this->name; } function setName($name) { $this->name = $name; }}?>
下面來檢查一下用複製運算符 = 建立的 $bar1 和用引用運算符 =& 建立的 $bar2 有沒有區別...
<?php$bar1 = new Foo('set in constructor');$bar1->echoName();$globalref[0]->echoName();/* 輸出:set in constructorset in constructorset in constructor */$bar2 =& new Foo('set in constructor');$bar2->echoName();$globalref[1]->echoName();/* 輸出:set in constructorset in constructorset in constructor */?>
顯然沒有區別,但實際上有一個非常重要的區別:$bar1 和 $globalref[0] 並沒有被引用,它們不是同一個變量。這是因為「new」預設並不返回引用,而返回一個複製。
注: 在返回複製而不是引用中並沒有效能上的損失(因為 PHP 4 及以上版本使用了引用計數)。相反更多情況下工作於複製而不是引用上更好,因為建立引用需要一些時間而建立複製實際上不花時間(除非它們都不是大的陣列或對象,而其中之一跟著另一個變,那使用引用來同時修改它們會更聰明一些)。
<?php// 現在改個名字,你預期什麼結果?// 你可能預期 $bar1 和 $globalref[0] 二者的名字都改了...$bar1->setName('set from outside');// 但如同前面說的,並不是這樣。$bar1->echoName();$globalref[0]->echoName();/* 輸出為:set from outsideset in constructor */// 現在看看 $bar2 和 $globalref[1] 有沒有區別$bar2->setName('set from outside');// 幸運的是它們不但相同,根本就是同一個變量。// 因此 $bar2->name 和 $globalref[1]->name 也是同一個變量。$bar2->echoName();$globalref[1]->echoName();/* 輸出為:set from outsideset from outside */?>
最後給出另一個例子,試著理解它。
<?phpclass A { function A($i) { $this->value = $i; // 試著想明白為什麼這裡不需要引用 $this->b = new B($this); } function createRef() { $this->c = new B($this); } function echoValue() { echo "<br />","class ",get_class($this),': ',$this->value; }}class B { function B(&$a) { $this->a = &$a; } function echoValue() { echo "<br />","class ",get_class($this),': ',$this->a->value; }}// 試著理解為什麼這裡一個簡單的複製會在下面用 *// 標出來的行中產生預期之外的結果$a =& new A(10);$a->createRef();$a->echoValue();$a->b->echoValue();$a->c->echoValue();$a->value = 11;$a->echoValue();$a->b->echoValue(); // *$a->c->echoValue();?>
上例將輸出:
class A: 10 class B: 10 class B: 10 class A: 11 class B: 11 class B: 11