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