 |
Создание
ссылок внутри конструктора может привести к неожиданным результатам. В этом разделе
сделана попытка помочь избежать проблем. 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 */ |
|  |