What It Is
The Builder pattern constructs a complex object step by step. Instead of one constructor with a long, confusing argument list, the builder offers small named steps — and a final build() that returns the finished object.
In PHP the steps return $this, so calls chain into a readable sentence.
Example: Building a Pizza
Compare (new PizzaBuilder("large"))->cheese()->topping("mushrooms") with a constructor like new Pizza("large", true, [...]) — the builder says what every value means, and optional parts are simply skipped.
Steps that chain
Every step is named and optional: the small pizza skips them all. No true, null, false argument soup — and the toppings print as a plain comma list, none when there are none.
Output: PHP script
<?php
class Pizza {
public function __construct(
public string $size,
public bool $cheese,
public array $toppings,
) {}
}
class PizzaBuilder {
private bool $cheese = false;
private array $toppings = [];
public function __construct(private string $size) {}
public function cheese(): self {
$this->cheese = true;
return $this;
}
public function topping(string $t): self {
$this->toppings[] = $t;
return $this;
}
public function build(): Pizza {
return new Pizza($this->size, $this->cheese, $this->toppings);
}
}
function describe(Pizza $p): void {
$toppings = $p->toppings === [] ? "none" : implode(", ", $p->toppings);
printf("%s pizza, cheese: %s, toppings: %s\n",
$p->size, var_export($p->cheese, true), $toppings);
}
$big = (new PizzaBuilder("large"))
->cheese()
->topping("mushrooms")
->topping("olives")
->build();
$small = (new PizzaBuilder("small"))->build();
describe($big);
describe($small);
When to Use It
Use it when an object has many optional parts, or when construction has real steps that deserve names. Requests, queries, and configurations are classic builder territory.
Skip it for simple objects — PHP's named arguments, new Pizza(size: "large"), already make a plain constructor read well for the easy cases.
Pros and Cons
Pros: readable construction; optional parts without giant argument lists; the object can be validated once, in build().
Cons: a second class to write and maintain; overkill where a plain constructor already reads well.