PHP Builder Pattern
A short screencast: the Builder pattern in PHP — assembling an immutable object through a fluent method chain without touching its constructor.
Overview
In this screencast we assemble a pizza without a long constructor. The Pizza class is immutable: all data is passed to the constructor at once. The PizzaBuilder class accumulates parameters step by step (size(), addTopping()), every step returns $this for method chaining, and build() finally creates the finished product.
UML diagram
Code
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();
Note: why a Builder
Constructors with a dozen parameters are hard to read, and their overloads that "skip" arguments are known as telescoping constructors. The Builder solves both: the method chain reads like a sentence, and the immutable product is produced in one build() call. On top of that, each step can validate its input before the object exists — a bad recipe never yields a half-baked pizza.
Example output
Running php demo.php in the terminal produces:
large pizza with pepperoni, olives
Advantages
- Builds a complex object step by step, readably.
- Separates construction from representation: one process yields different objects.
- Removes "telescoping" constructors with a dozen parameters.
- Handy for optional parts and default values.
When to use
- When an object has many optional parts or parameters.
- When an object is assembled over several steps rather than one call.
- When one construction algorithm must produce different representations.
- When you want to avoid long constructors.
Usage in Laravel
In Laravel the builder is Illuminate\Database\Query\Builder and Illuminate\Database\Eloquent\Builder: methods such as where(), join() and orderBy() assemble the SQL step by step, and it runs only when get() is called. The same approach powers Illuminate\Bus\PendingBatch for configuring a batch of jobs and Illuminate\Testing\TestResponse, where assertions are chained.