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

18 июля, 2020 13:13
Admin
19 июня, 2022 9:28

Иногда может потребоваться создать копию уже заполненного объекта, чтобы не устанавливать свойства заново. Для этого в PHP используется ключевое слово clone. Например, предположим ситуацию, что мы создали объект класса и заполнили часть его свойств:

<?php

class User {

    public $name;

    private $city;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function setCity($value)
    {
        $this->city = $value;
    }
}

$user = new User("Иван");
$user->setCity("Москва");

Рассмотрим следующие примеры клонирования объектов.

Удачный пример клонирования объекта

Предположим, что у Ивана есть сестра Маша, которая живет в том же городе. Чтобы не создавать объект заново, мы можем сделать копию уже существующего объекта и поменять только имя:

<?php

$user = new User("Иван");
$user->setCity("Москва");

$user2 = clone $user;
$user2->name = "Маша";

print_r($user);
print_r($user2);

В данном случае мы описали пример удачного клонирования объектов, поскольку в переменной $user2 у нас будет копия объекта $user, а не ссылка на него.

Неудачный пример клонирования объекта

Если в указанном выше примере убрать ключевое слово clone, то мы получим ссылку на объект $user, а не его копию:

<?php

$user = new User("Иван");
$user->setCity("Москва");

$user2 = $user;
$user2->name = "Маша";

print_r($user);
print_r($user2);

Тем самым, при изменении свойства name у объекта $user2 мы поменяем данное свойство и у объекта $user.

Изменения при клонировании объекта

С помощью магического метода __clone мы можем указать дополнительные действия, которые требуется выполнить при клонировании объекта. Например, мы можем сделать, чтобы при клонировании объекта User, его свойство name было пустой строкой:

<?php

class User {

    public $name;

    private $city;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function setCity($value)
    {
        $this->city = $value;
    }

    public function __clone()
    {
        $this->name = "";
    }
}

$user = new User("Иван");
$user->setCity("Москва");

$user2 = clone $user;

print_r($user);
print_r($user2);

Таким образом в переменной $user2 свойство name будет пустым.

Запрещаем клонирование

Чтобы запретить клонирование объектов класса, нам требуется сделать приватным магический метод __clone, таким образом пример ниже выдаст фатальную ошибку:

<?php

class User {

    public $name;

    private $city;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function setCity($value)
    {
        $this->city = $value;
    }

    private function __clone()
    {

    }
}

$user = new User("Иван");
$user->setCity("Москва");

$user2 = clone $user; // здесь будет ошибка