Шаблон Prototype (Прототип)
03-11-2019Время чтения ~ 2 мин.PHP/ООП 5662
Прототип — порождающий шаблон проектирования. Он используется для клонирования существующего объекта, вместо его инстанцирования с помощью new
. Нам повезло, что в PHP уже есть всё необходимое для Prototype — это языковая конструкция clone
, которая позволяет упростить реализацию праттерна до одной строчки.
Вообще может возникнуть вопрос, зачем вообще нужно клонирование, разве недостаточно обычного присваивания через равно «=»? Покажу на практическом примере.
Пусть у нас будет простой класс A с полем $val
и двумя методами: один для установки значения поля, другой для его вывода.
class A {
private $val;
public function set($val)
{
$this->val = $val;
}
public function out()
{
echo $this->val;
}
}
Теперь проверим как он работает:
// создаем объект
$a = new A;
// устанавливаем внутреннее поле
$a->set('hello');
// вывод
$a->out(); // hello
Всё вполне ожидаемо. Теперь попробуем сделать копию объекта $a
с помощью присваивания. Проверим что выводится в этом случае.
// получаем новую переменную $b
$b = $a;
// работаем с $b
$b->set('hi');
$b->out(); // hi
// проверяем что в $a
$a->out(); // hi
Неожиданно, так? Мы изменили объект $b
, но он поменял и состояние поля в $a
.
Так вот — в PHP операция присваивания объекта происходит по ссылке. То есть строчка $b = $a;
не создала новый объект, а лишь указала, что $b
ссылается на уже существующий $a
. Поэтому все операции с этими переменными происходят с единым объектом.
Но что же делать, если действительно требуется создать совершенно новый объект/переменную? В PHP используется clone
.
// создаем объект
$a = new A;
// устанавливаем внутреннее поле
$a->set('hello');
// вывод
$a->out(); // hello
// клонирование
$c = clone $a;
// устанавливаем свой вариант
$c->set('hi');
// проверяем
$c->out(); // hi
$a->out(); // hello
Здесь переменная $c
создана через клонирование другого объекта и после этого PHP будет считать их совершенно разными и несвязанными между собой.
Пример кода я разместил на гитхабе.
Клонирование может использоваться для случаев, когда нужно создать несколько объектов, инстанцирование которых затратная операция. В этом случае вначале делается один объект, происходит его начальная «тяжелая инициализация», а после объект клонируется для использования под разные задачи. Следует отметить, что в PHP копирование по ссылке для объектов сделано с целью оптимизации памяти, поскольку классы — достаточно сложные типы данных, которые требуют особого обращения. Поэтому клонирование — это способ быстрого получения отдельной копии, но за счёт дополнительного расхода памяти.