Шаблон Prototype (Прототип)
03-11-2019Reading time ~ 2 min.PHP/ООП 5152
Прототип — порождающий шаблон проектирования. Он используется для клонирования существующего объекта, вместо его инстанцирования с помощью 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 копирование по ссылке для объектов сделано с целью оптимизации памяти, поскольку классы — достаточно сложные типы данных, которые требуют особого обращения. Поэтому клонирование — это способ быстрого получения отдельной копии, но за счёт дополнительного расхода памяти.