Design Pattern: Builder Pattern in PHP

Build pattern separates the object construction process from the object representation. This makes object construction easy, and clients can create the object step by step.

That is why this pattern is suitable for complex object construction, as the construction responsibility is delegated to the producer/director and the builder.

This article demonstrates Builder pattern implementations in PHP. Check the following examples.

Implementation

Here is the process of implementing the Builder pattern in PHP-

  • Create the item class. Define properties according to requirements and define getter methods. 
  • Create builder class. Define the same properties as the item class. Define setter methods for the properties.
  • Finally, in the builder define a build method. This method will take all the properties, and pass that to the item class to create an item object.

Here is a simple example of the builder pattern.

<?php
// Builder pattern implementation in PHP

// Item class
class Item {
    public function __construct(private int $property1, private int $property2) {

    }

    public function getProperty1(): int {
        return $this->property1;
    }

    public function getProperty2(): int {
        return $this->property2;
    }
}

// Builder class
class Builder {
    private $property1;
    private $property2;

    public function setProperty1(int $property1): Builder {
        $this->property1 = $property1;
        return $this;
    }

    public function setProperty2(int $property2): Builder {
        $this->property2 = $property2;
        return $this;
    }

    public function build(): Item {
        return new Item($this->property1, $this->property2);
    }
}

// Demo
$builder = new Builder();
$item = $builder->setProperty1(200)
    ->setProperty2(9999)
    ->build();

var_dump($item->getProperty1(), $item->getProperty2());

We will get the following output when the above code is executed:

int(200)
int(9999)

Examples

Here are some examples of Builder pattern-

Example #1: Request Builder

In the next example, we will implement the Builder pattern for making HTTP requests (dummy). This will enable us to build the request step-by-step, and finally build the request object.

Request Class

  • Create file “Request.php”.
  • Define an enum for different HTTP methods- GET, POST, etc. These are just labels for identifying the request method.
  • Create class “Request”.
  • Define properties- URL, type, header, body. Accept these as param in the constructor and set these.
  • Define a static method “newBuilder” to generate a new builder object. We will need the builder in the next steps.
  • Define utility method “build”. This method is used to send requests.
<?php
// Request.php

namespace BigBoxCode\DesignPattern\Builder\Request;

use BigBoxCode\DesignPattern\Builder\Request\Builder;

enum RequestType {
    case GET;
    case POST;
    case PUT;
    case PATCH;
    case DELETE;
}

class Request {
    private string $url;
    private RequestType $type;
    private array $header = [];
    private array $body = [];

    public function __construct(Builder $builder) {
        $this->url = $builder->url;
        $this->type = $builder->type;
        $this->header = $builder->header;
        $this->body = $builder->body;
    }

    public function send(): void {
        echo "Sending Request...";
        echo "\n\nURL: " . $this->url;
        echo "\n\nType: " . print_r($this->type, true);
        echo "\n\nHeaders: " . print_r($this->header, true);
        echo "\n\nBody: " . print_r($this->body, true);

        // Write functional code to send request
    }

    public static function newBuilder(): Builder {
        return new Builder();
    }
}

Builder Class

  • Create file “Builder.php”.
  • Create class “Builder”.
  • Define properties the same as the “Request” class.
  • Define getter methods for the class properties.
  • Define a method named “build”. This method creates a new “Request” object and returns that.
<?php
// Builder.php

namespace BigBoxCode\DesignPattern\Builder\Request;

use BigBoxCode\DesignPattern\Builder\Request\Request;


class Builder {
    public string $url;
    public RequestType $type;
    public array $header = [];
    public array $body = [];

    public function url(string $url): Builder {
        $this->url = $url;
        return $this;
    }

    public function type(RequestType $type): Builder {
        $this->type = $type;
        return $this;
    }

    public function header(string $key, string $value): Builder {
        $this->header[$key] = $value;
        return $this;
    }

    public function body(string $key, string $value): Builder {
        $this->body[$key] = $value;
        return $this;
    }

    public function build(): Request {
        return new Request($this);
    }
}

Demo

To use the implementation, call the static method “newBuilder”. Then call the setter methods step by step.

Finally call the “build” method. This will return full request object.

Then we can call the “send” method to send request.

<?php
// demo.php

require __DIR__ . '/../../vendor/autoload.php';

use BigBoxCode\DesignPattern\Builder\Request\Request;
use BigBoxCode\DesignPattern\Builder\Request\RequestType;


$request = Request::newBuilder()
    ->url("https://bigboxcode.com/request-test")
    ->type(RequestType::POST)
    ->header("X-AUTH-TOKEN", "someTokenHere")
    ->header("X-SOME-HEADER", "someRandomHeaderValueHere")
    ->body("unit_id", "99")
    ->body("code", "88C3ABK")
    ->build();

// Send request
$request->send();

Output

Output will be as below. This output is coming from the debug code that we have written in the “send” method of the “Request” class.

Sending Request...

URL: https://bigboxcode.com/request-test

Type: Builder\Request\RequestType Enum
(
    [name] => POST
)


Headers: Array
(
    [X-AUTH-TOKEN] => someTokenHere
    [X-SOME-HEADER] => someRandomHeaderValueHere
)


Body: Array
(
    [unit_id] => 99
    [code] => 88C3ABK
)

Example #2: Vehicle Builder

Let’s work on a vehicle builder. Here we have “Car” and “Plane” classes. And we want to implement the Builder pattern for building objects of these classes.

Car Item Class

  • Create a file named “Car.php”.
  • Create class “Car”.
  • Define some properties as per requirement, and accept and set those in the constructor.
  • Define getter methods for the properties.
<?php
// Car.php

namespace BigBoxCode\DesignPattern\Builder\Vehicle;

class Car {
    public function __construct(
        private int $wheel,
        private int $engine,
        private int $seat,
        private int $door,
        private bool $interior) {
    }

    public function getWheel(): int {
        return $this->wheel;
    }

    public function getEngine(): int {
        return $this->engine;
    }

    public function getSeat(): int {
        return $this->seat;
    }

    public function getDoor(): int {
        return $this->door;
    }

    public function isInterior(): bool {
        return $this->interior;
    }

    public function __toString(): string {
        return "Car: Wheel -> " . $this->wheel . " | Engine -> " . $this->engine . " | Seat -> " . $this->seat . " | Door -> " . $this->door . " | Interior -> " . ($this->interior ? 'true' : 'false');
    }
}

Plane Item Class

  • Create file “Plane.php”.
  • Define class “Plane”.
  • Define private properties and set those in the constructor.
  • Define the getter methods for the defined properties.
<?php
// Plane.php

namespace BigBoxCode\DesignPattern\Builder\Vehicle;


class Plane {
    public function __construct(
        private int $wheel,
        private int $engine,
        private int $seat,
        private int $door,
        private int $wing,
        private bool $interior) {
    }

    public function getWheel(): int {
        return $this->wheel;
    }

    public function getEngine(): int {
        return $this->engine;
    }

    public function getSeat(): int {
        return $this->seat;
    }

    public function getDoor(): int {
        return $this->door;
    }

    public function getWing(): int {
        return $this->wing;
    }

    public function isInterior(): bool {
        return $this->interior;
    }

    public function __toString(): string {
        return "Plane: Wheel -> " . $this->wheel . " | Engine -> " . $this->engine . " | Seat -> " . $this->seat . " | Door -> " . $this->door . " | Wing: " . $this->wing . " | Interior -> " . ($this->interior ? 'true' : 'false');
    }
}

Vehicle Builder Interface

  • Create file “VehicleBuilder.php”.
  • Define an interface “VehicleBuilder”.
  • Declare classes that will work as setter for the properties of the item classes.
<?php
// VehicleBuilder.php

namespace BigBoxCode\DesignPattern\Builder\Vehicle;

interface VehicleBuilder {
    public function addWheel(int $noOfWheel): void;
    public function addEngine(int $noOfEngine): void;
    public function addSeat(int $noOfSeat): void;
    public function addInterior(): void;
    public function addDoor(int $noOfDoor): void;
    public function addWing(int $noOfWing): void;
}

Car Builder Class

  • Create file “CarBuilder.php”.
  • Define class “CarBuilder”.
  • Implement “VehicleBuilder” interface for the class.
  • Define properties that match with the “Car” class.
  • Define setter methods for the properties.
  • Define a “build” method that takes all the properties, passes that to the “Car” class, and generates a “Car” object.
<?php
// CarBuilder.php

namespace BigBoxCode\DesignPattern\Builder\Vehicle;


class CarBuilder implements VehicleBuilder {
    private int $wheel = 0;
    private int $engine = 0;
    private int $seat = 0;
    private bool $interior;
    private int $door = 0;

    public function addWheel(int $noOfWheel): void {
        echo "Add " . $noOfWheel . " wheels\n";

        $this->wheel += $noOfWheel;
    }

    public function addEngine(int $noOfEngine): void {
        echo "Add " . $noOfEngine . " engine\n";

        $this->engine += $noOfEngine;
    }

    public function addSeat(int $noOfSeat): void {
        echo "Add " . $noOfSeat . " Seat\n";

        $this->seat = $noOfSeat;
    }

    public function addInterior(): void {
        echo "Add interior\n";

        $this->interior = true;
    }

    public function addDoor(int $noOfDoor): void {
        echo "Add " . $noOfDoor . " door\n";

        $this->door += $noOfDoor;
    }

    public function addWing(int $noOfWing): void {
        throw new \Exception("Can not add wings");
    }

    public function build(): Car {
        return new Car($this->wheel, $this->engine, $this->seat, $this->door, $this->interior);
    }
}

Plane Builder Class

  • Create file “PlaneBuilder.php”.
  • Define class “PlaneBuilder”.
  • Implement “VehicleBuilder” interface for the “PlaneBuilder” class.
  • Define properties that match with the “Plane” class.
  • Define setter methods for the properties.
  • Define a “build” method that passes all the properties to “Plane” class, and generates a “Plane” object.
<?php
// PlaneBuilder.php

namespace BigBoxCode\DesignPattern\Builder\Vehicle;

class PlaneBuilder implements VehicleBuilder {
    private int $wheel = 0;
    private int $engine = 0;
    private int $seat = 0;
    private bool $interior;
    private int $door = 0;
    private int $wing = 0;

    public function addWheel(int $noOfWheel): void {
        echo "Add " . $noOfWheel . " wheels\n";

        $this->wheel += $noOfWheel;
    }

    public function addEngine(int $noOfEngine): void {
        echo "Add " . $noOfEngine . " engine\n";

        $this->engine += $noOfEngine;
    }

    public function addSeat(int $noOfSeat): void {
        echo "Add " . $noOfSeat . " Seat\n";

        $this->seat = $noOfSeat;
    }

    public function addInterior(): void {
        echo "Add interior\n";
        $this->interior = true;
    }

    public function addDoor(int $noOfDoor): void {
        echo "Add " . $noOfDoor . " door\n";

        $this->door += $noOfDoor;
    }

    public function addWing(int $noOfWing): void {
        echo "Add " . $noOfWing . " wing\n";

        $this->wing += $noOfWing;
    }

    public function build(): Plane {
        return new Plane($this->wheel, $this->engine, $this->seat, $this->door, $this->wing, $this->interior);
    }
}

Vehicle Producer Class

We can ignore this Producer and write all these code in the usage(client) part.

Create a producer for the vehicles.

  • Create a class named “VehicleProducer.php”.
  • Define class “VehicleProducer”.
  • Define methods “buildCar” and “buildPlane”. These methods accepts a builder object (CarBuilder or PlaneBuilder) then sets all the required values.
  • Finally the builder object is returned.
<?php
// VehicleProducer.php

namespace BigBoxCode\DesignPattern\Builder\Vehicle;

class VehicleProducer {
    public function buildCar(CarBuilder $carBuilder): CarBuilder {
        $carBuilder->addWheel(4);
        $carBuilder->addEngine(1);
        $carBuilder->addDoor(4);
        $carBuilder->addSeat(4);
        $carBuilder->addInterior();
        
        return $carBuilder;
    }

    public function buildPlane(PlaneBuilder $planeBuilder): PlaneBuilder {
        $planeBuilder->addWheel(3);
        $planeBuilder->addEngine(2);
        $planeBuilder->addDoor(4);
        $planeBuilder->addSeat(120);
        $planeBuilder->addInterior();

        try {
            $planeBuilder->addWing(2);
        } catch (\Exception $e) {
            throw new \RuntimeException($e);
        }

        return $planeBuilder;
    }
}

Demo

Create a producer object and then call the methods from the object to the producer vehicle.

<?php
// demo.php

require __DIR__ . '/../../vendor/autoload.php';

use BigBoxCode\DesignPattern\Builder\Vehicle\CarBuilder;
use BigBoxCode\DesignPattern\Builder\Vehicle\PlaneBuilder;
use BigBoxCode\DesignPattern\Builder\Vehicle\VehicleProducer;

$vehicleProducer = new VehicleProducer();

echo "Building Car:\n\n";

$carBuilder = new CarBuilder();
$vehicleProducer->buildCar($carBuilder);

$car = $carBuilder->build();
echo "\nFinal result:\n" . $car;


echo "\n\nBuilding Plane:\n\n";

$planeBuilder = new PlaneBuilder();
$vehicleProducer->buildPlane($planeBuilder);

$plane = $planeBuilder->build();
echo "\nFinal result:\n" . $plane;

Output

Output of the above demo code will be as below.

Building Car:

Add 4 wheels
Add 1 engine
Add 4 door
Add 4 Seat
Add interior

Final result:
Car: Wheel -> 4 | Engine -> 1 | Seat -> 4 | Door -> 4 | Interior -> true

Building Plane:

Add 3 wheels
Add 2 engine
Add 4 door
Add 120 Seat
Add interior
Add 2 wing

Final result:
Plane: Wheel -> 3 | Engine -> 2 | Seat -> 120 | Door -> 4 | Wing: 2 | Interior -> true

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Builder Pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.