Рассмотрим его последовательно. В нашем распоряжении есть класс MyFoo. В кон­структоре мы сохраняем ссылку на самих себя в this->me, кроме того, устанавливаем значение this->value равным 5.
В нашем распоряжении имеются три функции: одна из них устанавливает значение this->value, другая возвращает значение this->value и третья возвращает значение this->value->me. Но разве $this и $this->me это не одно и то же? Разве MyFoo::getValue() и MyFoo::getValueFromMe() всегда возвращают одно и то же?
Посмотрим внимательнее. Сначала вызовем функцию CreateObject("foo") , которая возвращает объект типа MyFoo. Затем вызовем MyFoo::setValue(7) и MyFoo::getValue() и MyFoo::getValueFromMe() , надеясь получить один и тот же результат - 7.
Конечно, если в обоих случаях мы получим 7, это будет одним из наиболее бездо­казательных примеров в истории книгопечатания, поэтому я абсолютно уверен, что читатель уже догадался, что результат, который со всей определенностью нами получен не будет, так это два числа 7.
Но какой же результат будет получен нами и, самое главное, почему?
В результате будут получены числа 7 и 5 соответственно. А почему - на это есть три веские причины.
Прежде всего рассмотрим конструктор. Находясь внутри конструктора, мы устанавливаем ссылку между this и this->me. Другими словами, this и this->me - виртуально одно и то же. Но основным элементом предложения является "находясь внутри конструктора'. Как только конструктор завершает работу, PHP выполняет работу по присвоению вновь созданного объекта (результат работы оператора new MyFoo, строка 28) obj. Так как объекты не являются специальными и обрабатываются как данные любого другого типа в PHP, присвоение значения X объекту Y означает сделать Y копией X. Другими словами, obj становится копией new MyFoo или копией объекта this, который располагается внутри конструктора. А как же насчет obj->me? Поскольку это ссылка, она останется нетронутой на протяжении процесса копирования и будет указывать на тот же объект, на который он указывал и до того, - this, который имеется у нас внутри конструктора. Да, именно так - obj и obj->me больше не будут суть одним и тем же. Изменение одного из них никак не влияет на другой.
Это была первая причина, а мы обещали сразу три. К счастью, вторая причина во многом подобна первой. Скажем так, что каким-то чудесным образом нам удалось решить проблему получения экземпляра объекта (строка 28). Поскольку возвращаемое значение CreateObject передавалось в global_object, то мы по-прежнему сталкиваемся с той же проблемой - global_object станет репликой возвращаемого значения, и опять global_object и global_object->me не будут одним и тем же (вторая причина).
Но в действительности нам не следовало заходить так далеко, так как не следовало разрушать связь, которую мы только что вернули из CreateObject как return $obj (строка 34; третья причина). Итак, что можно с этим сделать? Есть два варианта. Первый заключается в повсеместном добавлении амперсанта, как это сделано в листинге 6.22 (строки 24, 28, 31 и 37). Второй вариант заключается в том, что, если вам настолько повезло и в вашем распоряжении уже имеется PHP 5, нужно благодарить свою удачу и забыть обо всем этом, поскольку PHP 5 позаботится об этом сам. Наконец, если вас все еще интересует, как PHP 5 это делает, продолжим наше исследование. 

Листинг 6.22. Синдром WTMA в PHP 4

1 class MyFoo {
2 function MyFoo() 3{
4 $this->me = &$this;
5 $this->value = 2;
6} 7
8 function setValue($val)
9{
10 $this->value = $val;
11 } 12
13 function getValue()
14 {
15 return $this->value;
16 } 17
18 function getValueFromMe()
19 {
20 return $this->me->value;
21 }
22 }; 23
24 function &CreateObject($class_type)
25 {
26 switch ($class_type) {
27 case "foo":
28 $obj =& new MyFoo();
29 break;
30 case "bar":
31 $obj =& new MyBar();
32 break;
33 }
34 return $obj;
35 }
36
37 $global_obj =& CreateObject ("foo");
38 $global_obj->setValue(7); 39
4 0 print "Значение равно " . $global_obj->getValue() . "n";
41 print " Значение равно " . $global_obj->getValueFromMe() . "n"; 
PHP 5 является самой первой версией PHP, которая рассматривает объекты как сущности, совершенно непохожие на любые другие типы данных. С точки зрения конечного пользователя это реализовано достаточно простым способом - объекты в PHP 5 всегда передаются по ссылке, даже в случаях, когда все другие типы данных (такие как целые числа, строки или массивы) передаются значениями. Наиболее примечательно то, что для передачи ссылки на объекты уже нет необходимости использовать амперсанты.
При рассмотрении данного примера становится совершенно очевидной основная мотивация использования объектов. ООП заключается в широком использовании сетей объектов и сложных взаимоотношений между объектами, для чего требуется использование ссылок. Прозрачная репликация, которая применялась в предыдущих версиях PHP и имевшая смысл при работе со строками или с массивами, совершенно бесполезна и даже вредна при работе с объектами. Поэтому перенос объектов по умолчанию делается по ссылке, а копии создаются только в том случае, если это указано явными образом.
Как это сделано?
До PHP 5 значения всех типов сохранялись в специальной структуре zval (Zend VALue). Эти значения могут хранить простые значения, такие как числа или строки, и сложные значения, такие как массивы или объекты. При передаче в функции или возвращении из функций эти значения дублируются, создавая тем самым другие структуры с идентичным содержимым в другом месте в памяти.
В PHP 5 все значения по-прежнему хранятся аналогичным образом в структурах zval, за исключением объектов. Объекты размещаются в другом месте или в так называемом Object Store, и каждый имеет свой уникальный идентификационный номер или дескриптор. Структура zval, вместо того чтобы хранить сам объект, хранит дескриптор объекта. При репликации области zval, содержащей объект, в такой ситуации, как, например, при передаче объекта как аргумента функции, операция по копированию данных больше не выполняется. Мы просто сохраняем тот же дескриптор объекта и оповещаем Object Store, что на данный конкретный объект указывает другая область zval. Так как сам объект располагается в Object Store, любые внесенные нами изменения будут отражены во всех структурах zval, которые содержат этот дескриптор. Этот дополнительный уровень косвенной ссылки позволяет объектам PHP вести себя так, как будто они всегда прозрачно и эффективно передаются по ссылке.
Теперь вернемся к нашему примеру из листинга 6.21 и удалим все амперсанты, и все отлично заработает. В качестве специального вознаграждения нам больше не нужен амперсант при ссылке на самих себя внутри конструктора в строке 4.