__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: 0method __clone() вызывается для нового объекта после создания неглубокой копии. Здесь вы сбрасываете идентификаторы, create свежие копии вложенных объектов или выполняете необходимую очистку, чтобы clone был действительно независимым.
Задание
ЛегкоДавайте создадим систему версионирования документов, которая демонстрирует, как клонирование создаёт независимые копии и как магический метод __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. Содержимое клонированного документа
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн StrategyПотренируйтесь самостоятельно: Онлайн-компилятор PHP