Назначение объектов PHP и клонирование

Я знаю, что это описано в php docs, но я смутился с этой проблемой.

Из документов php:

$instance = new SimpleClass(); $assigned = $instance; $reference =& $instance; $instance->var = '$assigned will have this value'; $instance = null; // $instance and $reference become null var_dump($instance); var_dump($reference); var_dump($assigned); ?> 

Вышеприведенный пример выводит:

 NULL NULL object(SimpleClass)#1 (1) { ["var"]=> string(30) "$assigned will have this value" } 

ОК, поэтому я вижу, что $assigned исходный объект ( $instance ), которому присваивается значение null , поэтому явно $assigned не является ссылкой, а копией экземпляра $.

Так в чем разница между

  $assigned = $instance 

а также

  $assigned = clone $instance 

Объекты – абстрактные данные в памяти. Переменная всегда содержит ссылку на эти данные в памяти. Представьте себе, что $foo = new Bar создает экземпляр объекта Bar где-то в памяти, присваивает ему некоторый id #42 , а $foo теперь содержит этот #42 качестве ссылки на этот объект. Присвоение этой ссылки другим переменным по ссылке или обычно работает так же, как и с любыми другими значениями. Многие переменные могут содержать копию, если эта ссылка, но все указывают на один и тот же объект.

clone явно создает копию самого объекта, а не только ссылку, указывающую на объект.

 $foo = new Bar; // $foo holds a reference to an instance of Bar $bar = $foo; // $bar holds a copy of the reference to the instance of Bar $baz =& $foo; // $baz references the same reference to the instance of Bar as $foo 

Просто не путайте «ссылку», как в =& с «ссылкой», как в идентификаторе объекта .

 $blarg = clone $foo; // the instance of Bar that $foo referenced was copied // into a new instance of Bar and $blarg now holds a reference // to that new instance 

Разница между

  $assigned = $instance 

а также

  $assigned = clone $instance 

заключается в том, что при использовании ключевого слова clone вы можете использовать магический метод __clone (), который дает вам лучший контроль над клонированием объектов. Из руководства php:

После завершения клонирования, если метод __clone () определен, тогда будет вызываться метод __clone () вновь созданного объекта, чтобы разрешить любые необходимые свойства, которые необходимо изменить.

Более того, объекты в PHP 5 назначаются по ссылке, если вы хотите создать копию объекта, который вы должны использовать клон .

Из руководства :

Ссылка PHP – это псевдоним, который позволяет двум различным переменным писать одно значение. Начиная с PHP 5, объектная переменная больше не содержит объект как значение. Он содержит только идентификатор объекта, который позволяет объектным аксессуарам находить фактический объект. Когда объект отправляется аргументом, возвращенным или назначенным другой переменной, разные переменные не являются псевдонимами: они содержат копию идентификатора, которая указывает на тот же объект.

  $assigned = $instance 

Выше присваивается $ instance to $ assign, самый основной присваивающий.

  $assigned = clone $instance 

Это для клонирования объектов. Назначьте копию объекта $ instance to $ assign.

Без клонирования $ assign и $ instance имеют одинаковый идентификатор объекта, что означает, что они указывают на один и тот же объект.

ну, в основном эти переменные – не что иное, как указатели на пространство памяти, где находится объект. Если вы сохраните значение указателя в другом указателе, а затем сбросьте исходный указатель, ничего не произойдет с областью памяти, на которую они оба указали.

Хранение короткого и простого здесь:

Здесь $reference похож на псевдоним объекта $instance . Если изначально $assignment и $reference указывают на пространство данных для $instance объекта $instance .

И когда происходит изменение значения, которое указывает на $instance оно будет изменено повсюду.

Но когда $instance = null , здесь мы делаем $instance указывающий на null и поскольку $reference является псевдонимом, поэтому:

$ reference -> $ instance -> null ….

В то время как $assignment прежнему содержит указатель на пространство данных для объекта, созданного $instance , но теперь $instance больше не нуждается в том же.

PHP не управляет объектами так же, как управляет другими типами данных. Строка (или целое число, логическое значение, float или массив) непосредственно сохраняется в переменной. Когда значение переменной присваивается другой переменной, значение копируется 1 в новую переменную.

Например:

 $x = array('a'); $y = $x; // $x and $y are different and unrelated variables; they do not share anything $y[] = 'b'; print_r($y); // Array // ( // [0] => a // [1] => b // ) print_r($x); // Array // ( // [0] => a // ) 

Как PHP обрабатывает назначение объектов?

С другой стороны, объекты обрабатываются PHP с использованием уникальных идентификаторов. Когда объект присваивается переменной, идентификатор хранится в переменной, а не в фактическом объекте.

Когда значение переменной присваивается другой переменной, идентификатор копируется, а не сам объект. Это приводит к тому, что две переменные указывают на один и тот же объект.

Используя ваш пример, значения переменных $instance и $assigned равны, оба они содержат идентификатор одного и того же объекта. $reference , с другой стороны, является ссылкой, то есть псевдоним (другое имя) переменной $assigned . Вот почему оператор $instance = null; очищает содержимое переменных $reference и $assigned но не влияет на $instance переменной $instance а также объект, чей идентификатор хранится в нем.

Перед установкой $reference на null можно использовать любой из $instance , $assigned SimpleClass или reference для доступа к объекту SimpleClass созданному в первой строке вашего примера. Fe:

 $instance = new SimpleClass(); $assigned = $instance; $instance->var = '$assigned will have this value'; echo($instance->var); // It prints: // $assigned will have this value // $assigned is also modified because it is the same object echo($assigned->var); // It prints: // $assigned will have this value 

Подробнее о объектах и ​​ссылках PHP в документации.

Что происходит, когда $assigned = clone $instance ?

Оператор clone создает дубликат его операнда. Он создает новый объект и инициализирует все его свойства, присваивая им значения свойств исходного объекта. Это означает, что если объект clone содержит объекты как свойства, эти свойства дублируются простым присваиванием, а не клонированием. 2

 $assigned = clone $instance; 

После этого утверждения $assigned содержит другое значение, чем $instance потому что теперь они хранят идентификаторы разных объектов. Будучи разными объектами, изменения $instance не влияют на $assigned больше.

 $instance = new SimpleClass(); $instance->var = '$instance has this value'; $assigned = clone $instance; echo($assigned->var); // It prints: // $instance has this value $assigned->var = '$assigned has a different value'; echo($assigned->var); // It prints: // $assigned has a different value // $instance is not modified echo($instance->var); // It prints: // $instance has this value 

1 Это не совсем так. Для целей оптимизации массивы не копируются до тех пор, пока они не будут изменены (копирование при записи). Тем не менее, это подробная информация о реализации, и для этой дискуссии хорошо учитывать все значения, за исключением того, что объекты копируются, когда они назначены новой переменной.

2 Это также называется «мелким» клонированием. Чтобы получить «глубокий» клон (настоящий дубликат, который не имеет ничего общего с оригиналом), класс клонированного объекта, который имеет объекты как свойства, должен реализовать магический метод __clone() и клонировать свойства оригинала объект. Кроме того, классы этих свойств должны реализовывать __clone() и т. Д.

Он просто создает совершенно новый объект, который сохраняет свойства копируемого объекта. Он выполняет глубокую копию:

 $assigned = $instance; 

Это делает мелкую копию при копировании объекта из одного в другой:

 $assigned = clone $instance;