Как-то давно, когда только появился php5, я думал, что разобрался с ООП, а именно с присвоением объектов. Но из-за того, что много времени проводил с java стал под забывать как это работает в php5.
В штатном режиме, если всегда помнить о том, что в php5 присваивание происходит по ссылке, то нет никаких проблем, пока не используешь знак &.
http://www.php.net/manual/en/language.oop5.basic.php
<?php
class SimpleClass{}
class SimpleClass
{
// property declaration
public $var = 'a default value';
// method declaration
public function displayVar() {
echo $this->var;
}
}
?>
Но подлинный смысл раскрывается этим комментарием:
http://www.php.net/manual/en/language.oop5.basic.php#79856
Я позволил себе его вольно перевести:
В php необходимо думать о переменных как о ячейках памяти. У каждой переменной если имя, которое ссылается на ячейку памяти(переменную), где хранится значение простого типа: число, строка, массив, и т.д. Когда вы создаете ссылку(&), вы создаете второе имя, которое ссылается на ту же саму ячейку памяти. Когда вы присваиваете одну переменную другой, вы копируете содержимое ячейки памяти в другую ячейку памяти.
Но присваивание экземпляров классов(далее объект) происходит не так как присваивание простых типов. Объекты не хранятся в ячейках памяти, которые программист "видит" на прямую. Вместо этого в ячейке памяти хранится указатель на объект. Таким образом указатель ведет себя как примитивный тип.
Когда вы присваиваете значение ссылки объекта одной переменной другой, обе переменные могут менять состояние одного и того же объекта. Но переменные не являются ссылками на объект, т.к. если присвоить одной из переменных новое значение, то это не отразится на другой переменной.
<?php
// Assignment of an object
Class Object{
public $foo="bar";
};
$objectVar = new Object();
$reference =& $objectVar;
$assignment = $objectVar
//
// $objectVar --->+-----------+
// |(указатель1)----+
// $reference --->+-----------+ |
// |
// +-----------+ |
// $assignment -->|(указатель2)----+
// +-----------+ |
// |
// v
// Object(1):foo="bar"
//
?>
Значение переменной $assignment отличается от $objectVar, но эти значение ссылаются на один и тот же объект. Это поведение делает похожим на механизм передачи по ссылке. Если вы используете переменную $objectVar, чтобы поменять состояние объекта, то эти же изменения появятся и в переменной $assignment, т.к. они указывают на один и тот же объект.
<?php
$objectVar->foo = "qux";
print_r( $objectVar );
print_r( $reference );
print_r( $assignment );
//
// $objectVar --->+-----------+
// |(указатель1)----+
// $reference --->+-----------+ |
// |
// +-----------+ |
// $assignment -->|(указатель2)----+
// +-----------+ |
// |
// v
// Object(1):foo="qux"
//
?>
Но с передачей значения по ссылке (&) дело обстоит совсем иначе. Если вы обнулите $objectVar, вы замените значение указателя в ячейке памяти на NULL. Это означает, что $reference, которая ссылается на туже ячейку памяти, также будет NULL. Но $assignment, которая ссылается на другую ячейку памяти, будет так же хранить копию указателя на объект, и она не будет равна NULL.
<?php
$objectVar = null;
print_r($objectVar);
print_r($reference);
print_r($assignment);
//
// $objectVar --->+-----------+
// | NULL |
// $reference --->+-----------+
//
// +-----------+
// $assignment -->|(указатель2)----+
// +-----------+ |
// |
// v
// Object(1):foo="qux"
?>
К примеру, если взять java, где все переменные если ссылки на объекты, тот же пример выполняется так как и в php5 без символа &:
import java.util.*;
class ObjectReference {
public static void main(String[] args) {
class Obj {
int var = 1;
}
Obj objectVar = new Obj();
Obj reference = objectVar;
objectVar.var = 2;
System.out.println("objectVar.var="+objectVar.var);
System.out.println("reference.var="+reference.var);
objectVar = null;
if (reference == null) {
System.out.println("reference is null");
} else {
System.out.println("reference is not null");
}
}
}
ответ:
objectVar.var=2
reference.var=2
reference is not null