Паттерн Строитель в PHP
Короткий скринкаст: паттерн «Строитель» (Builder) — собираем неизменяемый объект по цепочке методов и не трогаем его конструктор.
Описание
В этом скринкасте мы собираем пиццу без длинного конструктора. Класс Pizza неизменяем: все данные передаются в конструктор сразу. Класс PizzaBuilder накапливает параметры шагами (size(), addTopping()), каждый шаг возвращает $this для цепочки вызовов, а метод build() в конце создаёт готовый продукт.
UML-диаграмма
Код
Pizza.php
class Pizza
{
public function __construct(
private readonly string $size,
private readonly array $toppings
) {}
public function describe(): string
{
return $this->size . ' pizza with ' . implode(', ', $this->toppings);
}
}
PizzaBuilder.php
class PizzaBuilder
{
private string $size = 'medium';
private array $toppings = [];
public function size(string $size): self
{
$this->size = $size;
return $this;
}
public function addTopping(string $topping): self
{
$this->toppings[] = $topping;
return $this;
}
public function build(): Pizza
{
return new Pizza($this->size, $this->toppings);
}
}
demo.php
require_once 'Pizza.php';
require_once 'PizzaBuilder.php';
$pizza = (new PizzaBuilder())
->size('large')
->addTopping('pepperoni')
->addTopping('olives')
->build();
echo $pizza->describe();
Заметка: зачем Строитель
Длинные конструкторы с десятком параметров нечитаемы, а их перегрузки с «пропуском» аргументов называют телескопическими. Строитель решает обе проблемы: цепочка методов читается как предложение, а неизменяемый продукт получается в одном вызове build(). Плюс каждый шаг может проверить данные до того, как объект будет создан, — неудачный рецепт не даст родить «полуготовую» пиццу.
Пример результата
После php demo.php в терминале появится:
large pizza with pepperoni, olives
Преимущества
- Позволяет собирать сложный объект пошагово и читаемо.
- Отделяет конструирование от представления: один и тот же процесс даёт разные объекты.
- Избавляет от «телескопических» конструкторов с десятком параметров.
- Удобен для необязательных частей и значений по умолчанию.
Когда использовать
- Когда у объекта много необязательных частей или параметров.
- Когда объект собирается за несколько шагов, а не одним вызовом.
- Когда один алгоритм сборки должен создавать разные представления.
- Когда важно избежать длинных конструкторов.
Использование в Laravel
В Laravel Строитель — это Illuminate\Database\Query\Builder и Illuminate\Database\Eloquent\Builder: методы where(), join() и orderBy() шаг за шагом собирают SQL-запрос, а выполняется он только при вызове get(). Тот же приём — в Illuminate\Bus\PendingBatch для настройки пачки задач и в Illuminate\Testing\TestResponse, где проверки выстраиваются цепочкой.