Design Pattern: Facade Pattern in PHP

Facade introduces a new interface for the client to interface with the underlying complex subsystem classes. This is a high-level interface that hides the subsystems from the clients.

Facade uses the objects and method from the already existing class(subsystem) objects. It is the responsibility of the facade, to provide the desired functionality to the client, with simplicity.

This article is about the Facade pattern implementation in PHP. Check the implementation details and examples.

Implementation

Follow the steps below to implement Facade pattern in PHP-

  • Create a facade class.
  • Define private property for each of the subsystem classes and initialize those properties with new objects in the facade constructor.
  • In the method implementations, call the methods from the subsystem objects whenever needed. Add additional steps of code if required.
  • In the client use the create a facade class object and use that object.

Here is a simple example of Facade implementation-

<?php
// Facade pattern in PHP

// First subsystem
class Subsystem1 {
    public function operation1(): void {
        echo "Subsystem 1: operation 1\n";
    }

    public function operation2(): void {
        echo "Subsystem 1: operation 2\n";
    }
}

// Second subsystem
class Subsystem2 {
    public function operation3(): void {
        echo "Subsystem 2: operation 3\n";
    }

    public function operation4(): void {
        echo "Subsystem 2: operation 4\n";
    }
}

// Third subsystem
class Subsystem3 {
    public function operation5(): void {
        echo "Subsystem 3: operation 5\n";
    }
}

// Facade
class Facade {
    private Subsystem1 $subsystem1;
    private Subsystem2 $subsystem2;
    private Subsystem3 $subsystem3;

    public function __construct() {
        // Initialize subsystems
        $this->subsystem1 = new Subsystem1();
        $this->subsystem2 = new Subsystem2();
        $this->subsystem3 = new Subsystem3();
    }

    public function exampleOp1(): void {
        // Use operation from subsystem as required
        $this->subsystem1->operation1();
        $this->subsystem2->operation3();
    }

    public function exampleOp2(): void {
        // Use operation from subsystem as required
        $this->subsystem1->operation2();
        $this->subsystem3->operation5();
    }
}

// Demo
$facade = new Facade();

$facade->exampleOp1();
$facade->exampleOp2();

Output of the above code will be –

Subsystem 1: operation 1
Subsystem 2: operation 3

Subsystem 1: operation 2
Subsystem 3: operation 5

Examples

Here are a few examples of Facade pattern in PHP-

Example #1: Travel Plan

We have some classes for travel related operation- Car, Direction, Toll, Weather etc. We want to implement a facade for making it simpler to use all those subsystem classes.

Car Class [subsystem class]

  • Create file “Car.php”.
  • Define class “Car” and implement required methods.
<?php
// Car.php

namespace BigBoxCode\DesignPattern\Facade\TravelPlan;

class Car {
    public function startEngine(): void {
        echo "Start Engine\n";
    }

    public function stopEngine(): void {
        echo "Stop Engine\n";
    }

    public function goStraight(): void {
        echo "Go Straight: ↑\n";
    }

    public function goLeft(): void {
        echo "Go Left: ←\n";
    }

    public function goRight(): void {
        echo "Go Right: →\n";
    }

    public function getDistanceTravelled(): float {
        // This is some random calculation for demo purpose
        return ((rand(0, 180) * ((10000 - 100) * 10 + 1)) + 100 * 10) / 10.0;
    }
}

Direction Class [subsystem class]

  • Create file “Direction.php”.
  • Define class “Direction”.
  • Define methods as per requirement.
<?php
// Direction.php

namespace BigBoxCode\DesignPattern\Facade\TravelPlan;

use BigBoxCode\DesignPattern\Facade\TravelPlan\Point;

class Direction {
    public function __construct(
        private float $startLat,
        private float $startLng,
        private float $endLat,
        private float $endLng
    ) {
    }

    public function getLocationDetails(float $lat, float $lng) {
        echo "Country: ABC\n";
        echo "City: DEF\n";
        echo "State: GHI\n";
        echo "Zip: 101010\n";
    }

    public function getCurrentLocation(): Point {
        // This is some random calculation for demo purpose
        $currentLat = rand(0, 180);
        $currentLng = rand(0, 180);

        return new Point($currentLat, $currentLng);
    }

    public function getNextMove(): string {
        // This is some random calculation for demo purpose
        $nextMoves = ["straight", "left", "right"];
        return $nextMoves[rand(0, 2)];
    }

    public function getFullRoute(): array {
        $points = [];

        for ($i = 0; $i < 10; $i++) {
            // This is some random calculation for demo purpose
            $currentLat = (rand(0, 180) * ((90 - (-90) * 10 + 1) - 90 * 10)) / 10.0;
            $currentLng = (rand(0, 180) * ((180 - (-180) * 10 + 1) - 180 * 10)) / 10.0;

            $points[$i] = new Point($currentLat, $currentLng);
        }

        return $points;
    }
}

Toll Class [subsystem class]

  • Create file “Toll.php”.
  • Define class “Toll”.
<?php
// Toll.php

namespace BigBoxCode\DesignPattern\Facade\TravelPlan;

use BigBoxCode\DesignPattern\Facade\TravelPlan\Point;

class Toll {
    public function getTollPoints(float $lat, float $lng): array {
        $points = [];

        for ($i = 0; $i < 10; $i++) {
            // This is some random calculation for demo purpose
            $currentLat = rand(0, 180);
            $currentLng = rand(0, 180);

            $points[$i] = new Point($currentLat, $currentLng);
        }

        return $points;
    }

    public function getTollAmount(float $tollPointId): float {
        // This is some random calculation for demo purpose
        return rand(0, 100);
    }

    public function getTotalToll(float $lat, float $lng): float {
        // This is some random calculation for demo purpose
        return rand(0, 100);
    }
}

Weather Class [subsystem class]

  • Create file “Weather.php”.
  • Create class “Weather”.
<?php
// Weather.php

namespace BigBoxCode\DesignPattern\Facade\TravelPlan;

class Weather {
    public function getWeatherInfo(float $lat, float $lng): void {
        echo "Temperature: 20.7\n";
        echo "Precipitation: 1%\n";
        echo "Humidity: 73%\n";
        echo "Wind: 8 km/h\n";
    }
}

Facade Class

  • Create file “TravelFacade.php”.
  • Create class “TravelFacade”.
  • Declare private properties for objects of type “Car”, “Toll”, “Weather”, and “Direction”. In the constructor initialize the properties and assign an object of relevant class.
  • Define methods and use the methods from the objects of the subsystems (Car, Toll, Weather, Direction).
<?php
// TravelFacade.php

namespace BigBoxCode\DesignPattern\Facade\TravelPlan;

class TravelFacade {
    private float $startLat;
    private float $startLng;

    private float $endLat;
    private float $endLng;

    private Direction $direction;
    private Toll $toll;
    private Car $car;
    private Weather $weather;

    // define constructor
    public function __construct(float $startLat, float $startLng, float $endLat, float $endLng) {
        $this->startLat = $startLat;
        $this->startLng = $startLng;
        $this->endLat = $endLat;
        $this->endLng = $endLng;

        // Initialize classes
        $this->direction = new Direction($startLat, $startLng, $endLat, $endLng);
        $this->car = new Car();
        $this->toll = new Toll();
        $this->weather = new Weather();
    }

    public function getRoute(): array {
        return $this->direction->getFullRoute();
    }

    public function getLocationInfo(float $lat, float $lng): void {
        $this->direction->getLocationDetails($lat, $lng);
        $this->weather->getWeatherInfo($lat, $lng);
    }

    public function getCurrentLocation(): Point {
        return $this->direction->getCurrentLocation();
    }

    public function operateCar(): void {
        $fullRoute = $this->direction->getFullRoute();

        $this->car->startEngine();

        foreach ($fullRoute as $point) {
            $nextMove = $this->direction->getNextMove();

            switch ($nextMove) {
                case "straight":
                    $this->car->goStraight();
                    break;
                case "left":
                    $this->car->goLeft();
                    break;
                case "right":
                    $this->car->goRight();
                    break;
            }
        }

        $this->car->stopEngine();
    }

    public function getTotalTollAmount(float $lat, float $lng) {
        echo "Total Toll Amount: " . $this->toll->getTotalToll($lat, $lng) . "\n";
    }

}

Demo

We just need to create a facade object and call the methods from the object.

<?php
// demo.php

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

use BigBoxCode\DesignPattern\Facade\TravelPlan\TravelFacade;

$travelFacade = new TravelFacade(10, 10, 20, 30);

$currentLocation = $travelFacade->getCurrentLocation();

echo "Current Latitude: " . $currentLocation->getLat() . "\n";
echo "Current Longitude: " . $currentLocation->getLng() . "\n";


$travelFacade->getLocationInfo(20, 30);

$travelFacade->getTotalTollAmount(20, 30);

$travelFacade->operateCar();

Output

Output of the above demo code will be as below. Output may differ for you as most of the methods here use dummy(with random) code.

Current Latitude: 37
Current Longitude: 129


Country: ABC
City: DEF
State: GHI
Zip: 101010
Temperature: 20.7
Precipitation: 1%
Humidity: 73%
Wind: 8 km/h


Total Toll Amount: 56


Start Engine
Go Left: ←
Go Right: →
Go Right: →
Go Left: ←
Go Straight: ↑
Go Right: →
Go Right: →
Go Straight: ↑
Go Straight: ↑
Go Right: →
Stop Engine

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Facade pattern implementation in other programming languages.

Leave a Comment


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