Решение типового варианта контрольной работы Аналитическая геометрия Линейная алгебра Вычислить пределы функций Найти неопределенные интегралы Решить дифференциальные уравнения Вычислить двойной интеграл Задачник по математике
Учебник РНР
НазадГлава 13. Классы и ОбъектыВперёд

Ссылки внутри конструктора

Создание ссылок внутри конструктора может привести к неожиданным результатам. В этом разделе сделана попытка помочь избежать проблем.

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 */

Назад Оглавление Вперёд
Магические функции
__sleep и __wakeup
ВверхСсылки. Разъяснения.