Сайт вебмастера

Шаблон 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 копирование по ссылке для объектов сделано с целью оптимизации памяти, поскольку классы — достаточно сложные типы данных, которые требуют особого обращения. Поэтому клонирование — это способ быстрого получения отдельной копии, но за счёт дополнительного расхода памяти.

Related Posts