Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама
Senior ООП

Як працює clone в PHP і чим небезпечна поверхнева копія?

clone $obj створює новий об'єкт з тими самими значеннями властивостей. Але копія поверхнева: якщо властивість містить інший об'єкт, копіюється лише посилання на нього - обидва об'єкти ділять той самий вкладений об'єкт.

final class Order
{
    public function __construct(public DateTime $createdAt, public array $items) {}
}

$a = new Order(new DateTime('2026-01-01'), ['book']);
$b = clone $a;

$b->items[] = 'pen';                 // масив скопійовано: $a->items не змінився
$b->createdAt->modify('+1 day');     // об'єкт спільний: $a->createdAt теж змінився!

Масиви копіюються (за значенням), об'єкти всередині - ні.

__clone() викликається на копії після клонування - там роблять глибоку копію вкладених об'єктів:

public function __clone(): void
{
    $this->createdAt = clone $this->createdAt;
}

Де це стає проблемою:

  • «Незмінні» об'єкти з змінюваними частинами. Wither, що робить clone $this і змінює одне поле, ділить усі вкладені змінювані об'єкти з оригіналом.
  • Ресурси й з'єднання. Клон об'єкта з відкритим файлом чи з'єднанням з базою ділить той самий ресурс; закриття в одному ламає інший.
  • Ідентичність: клон Eloquent-моделі зберігає той самий первинний ключ. Для копії запису в базі є replicate().

Як уникнути проблем: робити вкладені значення незмінними (DateTimeImmutable, readonly value objects) - тоді поверхнева копія безпечна. З PHP 8.3 readonly-властивості можна переприсвоїти в __clone(), а PHP 8.5 додав clone($obj, ['prop' => $value]) для «зміненої копії» без ручного __clone.

Докладніше в документації: Клонування об'єктів

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання