Создание ссылок в конструкторе может привести к конфузу. Эта секция - своего рода памятка "как избежать проблем".
<?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('set in constructor');
$bar1->echoName();
$globalref[0]->echoName();
/* вывод:
set in constructor
set in constructor
set in constructor */
$bar2 =& new Foo('set in constructor');
$bar2->echoName();
$globalref[1]->echoName();
/* output:
set in constructor
set in constructor
set in constructor */
?>
На первый взгляд никакой разницы, но факт в том, что $bar1 и $globalref[0] _НЕ_ связаны, они НЕ являются одной и той-же переменной. Это потому, что "new" возвращает не ссылку, а копию.
Для доказательства того, что написано выше, посмотрим код ниже.Замечание: При возврате копии вместо ссылки нет никакой потери производительности (с PHP 4 и выше используется подсчет ссылок). Напротив, чаще всего лучше просто работать с копиями вместо ссылок, потому что создание ссылки требует времени, тогда как создание копии создание копий практически не занимает времени (за исключением когда работа идет с огромным массивом или объектом, которые изменяются и это изменение должно отразиться на всех остальных. Тогда, конечно, лучше использовать ссылки).
<?php
// теперь мы изменим name. какого поведения вы ожидаете?
// вы ждете, что и $bar1 и $globalref[0] изменят name...
$bar1->setName('set from outside');
// как объяснено выше - не в этот раз.
$bar1->echoName();
$globalref[0]->echoName();
/* вывод:
set from outside
set in constructor */
// давайте повторим этот же фокус с $bar2 и $globalref[1]
$bar2->setName('set from outside');
// повезло! Они не только идентичны, они являются одной и той же переменной,
// так что $bar2->name и $globalref[1]->name являются одним и тем же
$bar2->echoName();
$globalref[1]->echoName();
/* вывод:
set from outside
set from outside */
?>
Еще один, последний, пример. Попробуйте в нем разобраться.
<?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