При присваивании объекта класса другой переменной создается новая ссылка на тот же объект. Например:
class Person{ public $name; function __construct($name){ $this->name = $name; } } $tom = new Person("Tom"); $bob = $tom; $bob->name = "Bob"; echo $tom->name; // Bob
В данном случае после присваивания $bob = $tom;
обе переменных будут указывать на один и тот же объект. Поэтому
если мы поменяем свойство $name
у одной переменной, то это изменение затронет и другую переменную. Так как они ссылаются на один и тот же
объект.
Однако такое поведение может быть нежелательным, если мы хотим, чтобы после копирования переменные представляли независимые друг от друга объекты. И для этого PHP предоставляет оператор clone:
class Person{ public $name; function __construct($name){ $this->name = $name; } } $tom = new Person("Tom"); $bob = clone $tom; // копируем объект из $tom в переменную $bob $bob->name = "Bob"; echo $tom->name; // Tom
При применении оператора clone
все свойства, которые представляют примитивные типы и массивы, копируются в новый объект.
Однако, что если у нас свойство класса представляет другой класс:
class Company{ public $name; function __construct($name){ $this->name = $name; } } class Person{ public $name, $company; function __construct($name, $company) { $this->name = $name; $this->company = $company; } } $microsoft = new Company("Microsoft"); $tom = new Person("Tom", $microsoft); $bob = clone $tom; // копируем объект из $tom в переменную $bob $bob->name = "Bob"; $bob->company->name = "Google"; // изменяем у Боба название компании $bob->languages[0] = "french"; echo $tom->company->name; // Google - у Тома тоже изменилась компания
Здесь в принципе мы сталкиваемся с той же ситуацией, что и в первом примере. Класс Person содержит свойство, которое представляет класс Company. При клонировании объекта:
$bob = clone $tom;
Обе переменных $tom и $bob будут содержать ссылку на один и тот же объект Company. Соответственно если через одну переменную изменить свойства этого объекта:
$bob->company->name = "Google";
то изменение затронет и другую переменную:
echo $tom->company->name; // Google
Чтобы выйти из этой ситуации, необходимо в классе определить метод __clone. Он вызывается при клонировании и может применяться для клонирования вложенных объектов:
class Company{ public $name; function __construct($name){ $this->name = $name; } } class Person{ public $name, $company; function __construct($name, $company) { $this->name = $name; $this->company = $company; } function __clone() { $this->company = clone $this->company; } } $microsoft = new Company("Microsoft"); $tom = new Person("Tom", $microsoft); $bob = clone $tom; // копируем объект из $tom в переменную $bob $bob->name = "Bob"; $bob->company->name = "Google"; // изменяем у Боба название компании $bob->languages[0] = "french"; echo $tom->company->name; // Microsoft - у Тома НЕ изменилась компания