Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 48 из 91.

Когда вы присваиваете один объект другой переменной в PHP, вы не создаёте копию — обе переменные указывают на один и тот же объект. Чтобы создать действительно независимую копию, необходимо использовать ключевое слово clone:

<?php
class Product {
    public function __construct(
        public string $name,
        public float $price
    ) {}
}

$original = new Product("Laptop", 999.99);
$copy = clone $original;

$copy->price = 899.99;
echo $original->price . " - " . $copy->price;

Результат:

999.99 - 899.99

По умолчанию PHP выполняет неглубокую копию — он копирует все значения свойств напрямую. Это отлично работает со скалярными значениями, но объекты внутри вашего объекта по-прежнему ссылаются на тот же экземпляр. magic method __clone() позволяет настроить это поведение:

<?php
class Order {
    public function __construct(
        public int $id,
        public array $items = []
    ) {}
    
    public function __clone(): void {
        $this->id = 0;
        $this->items = [];
    }
}

$order1 = new Order(101, ["Book", "Pen"]);
$order2 = clone $order1;

echo "Original: " . $order1->id . ", Clone: " . $order2->id;

Результат:

Original: 101, Clone: 0

method __clone() вызывается для нового объекта после создания неглубокой копии. Здесь вы сбрасываете идентификаторы, create свежие копии вложенных объектов или выполняете необходимую очистку, чтобы clone был действительно независимым.

challenge icon

Задание

Легко

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

Вы организуете код в двух файлах:

  • Document.php: создайте класс Document, представляющий versioned документ. Используйте constructor promotion, чтобы определить публичное свойство $title (string), публичное свойство $content (string) и публичное свойство $version (целое число со значением по умолчанию 1). Добавьте private свойство $createdAt, хранящее текущую метку времени (используйте date('Y-m-d H:i:s') в конструкторе). Вашему документу необходимы:
    • getCreatedAt(): возвращает метку времени creation
    • __clone(): когда документ клонируется, version должна увеличиться на 1, а $createdAt должна быть сброшена на текущую метку времени (клон — это новая version, созданная "now")
  • main.php: подключите файл Document. Вы получите три входных значения: title, content и новую строку content для cloned version. Создайте Document с title и content. Затем клонируйте его, чтобы создать новую version, и обновите content клона, указав новую строку content. Выведите четыре строки:
    • version original документа
    • version cloned документа
    • content original документа
    • content cloned документа

Эта система показывает, как __clone() позволяет управлять происходящим во время клонирования. Original документ сохраняет свою version и время creation, а clone автоматически становится новой version со свежей меткой времени — это идеально подходит для отслеживания истории документа, где каждый clone представляет новую revision.

Попробуйте сами

<?php

require_once 'Document.php';

// Считать входные данные
$title = trim(fgets(STDIN));
$content = trim(fgets(STDIN));
$newContent = trim(fgets(STDIN));

// TODO: Создать Document с заголовком и содержимым

// TODO: Клонировать документ для создания новой версии

// TODO: Обновить содержимое клона новой строкой содержимого

// TODO: Вывести четыре строки:
// 1. Версия оригинального документа
// 2. Версия клонированного документа
// 3. Содержимое оригинального документа
// 4. Содержимое клонированного документа

?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор PHP