Копирование объектов классов

Последнее обновление: 31.03.2021

При присваивании объекта класса другой переменной создается новая ссылка на тот же объект. Например:

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 - у Тома НЕ изменилась компания
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850