|
Создание ссылок внутри конструктора может привести к неожиданным результатам.
В этом разделе сделана попытка помочь избежать проблем. 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, которая создана
с использованием copy = operator и $bar2, которая создана с использованием
reference =& operator...
$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();
/* вывод:
set in constructor
set in constructor
set in constructor */ |
Очевидной разницы нет, но фактически - очень значительная: $bar1 и
$globalref[0] это _НЕ_ ссылки, это НЕ одна и та же переменная. Это из-за того, что "new" не
возвращает ссылку по умолчанию, а возвращает копию.
Примечание:
здесь нет потери производительности (поскольку PHP 4 и более поздние
используют подсчёт ссылок) при возвращении копий вместо ссылок. Наоборот,
часто намного лучше работать с копиями вместо ссылок, так как создание
ссылок занимает некоторое время, а создание копий практически не требует
времени (если только они не большие массивы и не изменяются
последовательно одна за другой, тогда нужно использовать ссылки для изменения их всех).
Чтобы проверить то, что написано выше, давайте рассмотрим следующий код:
// теперь мы будем изменять имя. что можно ожидать?
// можно ожидать, что $bar1 и $globalref[0] изменят свои имена...
$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 */ |
Последний пример. Попытайтесь в нём разобраться.
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;
}
}
// попытайтесь понять, почему использование простой копии здесь даст
// нежелательный результат в строке *-marked
$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();
/*
output:
class A: 10
class B: 10
class B: 10
class A: 11
class B: 11
class B: 11
*/ |
| |