Създаването на референции в конструктора може да доведе до объркващи резултати. Този раздел, написан във вид на ръководство, може да ви помогне да избегнете подобни проблеми.
<?php
class 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('установяване в конструктора');
$bar1->echoName();
$globalref[0]->echoName();
/* изход:
установяване в конструктора
установяване в конструктора
установяване в конструктора */
$bar2 =& new Foo('установяване в конструктора');
$bar2->echoName();
$globalref[1]->echoName();
/* изход:
установяване в конструктора
установяване в конструктора
установяване в конструктора */
?>
Очевидно няма разлика, но всъщност има една значителна разлика: $bar1 и $globalref[0] не са извикани по референция и не са една и съща променлива. Това е така, тъй като операторът "new" по подразбиране връща не референция, а копие.
Забележка: Няма намаляване на производителността (след като от PHP 4 се използва брояч на референциите) при връщане на копия вместо референции. Точно обратното, често е по-добре просто да се работи с копия, вместо с референции, тъй като създаването на референции отнема известно време, докато създаването на копие фактически не отнема време (освен ако никое от тях не е голям масив или обект и един от тях е променен, а в последствие и останалите. В този случай ще бъде по-добре да се използват референции, за да бъдат променени едновременно).
За да докажем написаното по-горе, нека погледнем кода отдолу.
<?php
// сега ще променим името. Какво очаквате да стане?
// можете да очаквате, че $bar1 и $globalref[0] ще са с променени имена...
$bar1->setName('установяване от вън');
// както споменахме по-горе, това няма да стане
$bar1->echoName();
$globalref[0]->echoName();
/* изход:
установяване от вън
установяване в конструктора */
// нека сега видим каква е разликата между $bar2 и $globalref[1]
$bar2->setName('установяване от вън');
// за щастие те не само са равни, те представляват една и съща променлива
// така че, $bar2->name и $globalref[1]->name също са една и съща променлива
$bar2->echoName();
$globalref[1]->echoName();
/* изход:
установяване от вън
установяване от вън */
?>
Още един, последен пример, опитайте се да го разберете.
<?php
class 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