Factory Pattern in PHP | Learn Design Patterns in 2022

Factory Pattern in PHP

The Factory pattern in PHP will make sense only if you understand the factory design pattern in general. Here’s a glimpse of the final design diagram from the article.

Factory Pattern in PHP
BookACar Application Design Diagram

We will build this design incrementally and will implement it in PHP. Join us in this exciting journey of developing a car booking application using factory pattern in PHP.

Factory Pattern in PHP Definition Described

Factory design pattern in PHP is a creational design pattern that defines a method for object creation in a superclass and delegates the instantiation to its sub-classes.”

Factory Design Pattern
Factory Design Pattern

The objective of this pattern is to encapsulate the object creation logic in a module and separate it from the core business logic.

Sounds abstract? Don’t worry, as this article will not only help you understand the factory pattern in PHP really well but also open up ways for you to develop more design-oriented flexible software systems.

BookACar Application | A Real World Example of Factory Pattern in PHP

BookACar | The First Release

So, you have been a lead developer in one of the thriving startups, BookACar. It helps customers to book and purchase a car of their favorite type and brand. The application has yet to become popular, so at the moment, it’s a collaboration with one brand. 

You’re tempted to come up with an MVP as soon as possible, and guess what? Your team may end up releasing the application with code like this.

Factory Pattern in PHP
BookACar Application First Version

But there is more than one type of Car…

Oops! Guess what? Some requirements still need to be included. There is more than one type of car. 

Types of Cars
Types of Cars

But the code above doesn’t deal with this. So, time for another iteration. This time developers refactor it like this.

Factory Pattern in PHP
Refactored Code

Technically, nothing is wrong with this implementation. But, from a design POV, there are better ways to handle it.

So, What’s Wrong with this Implementation?

The implementation above violates two fundamental design principles.

Single Responsibility Pattern 

Single Responsibility Pattern says a module should have one and only one job. The implementation above delegates objects initialization to the orderCar() module. Ideally, this module should focus on booking a car rather than initializing cars.

Single Responsibility Principle
Single Responsibility Principle

Open-Closed Principle

Open-Closed Principle says that modules should be open to extension but closed for modification.

The implementation above initializes concrete objects of a more abstract Car type.

Factory Pattern in PHP
Concrete Car Classes

Coding like this would end up in a maintenance nightmare when there are changes such that you need to add or remove concrete classes. You have no option but to modify the existing modules to make those changes. 

Let’s say that the car brand discontinues minivans and introduces hatchback cars.

Factory Pattern in PHP
Updated Car CATA

How will you accommodate this change? At the moment, there’s one way, and that’s how it is.

Open-Closed Principle
Violate Open-Closed Principle

See how a few changes messed up the existing code. Imagine if you have been using the same initialization code in 10 other application modules. Sounds horrible, right?

Encapsulate the Change

Change is inevitable in software development. You can’t escape it, but you can certainly encapsulate it. 

But what do we mean by encapsulating the change? Putting it in simpler terms, it aggregates your applications’ frequently changing aspects into a separate module. 

How is that helpful? So, when you encapsulate the change, you contain it in one place, and it doesn’t ripple out to the rest of your application, as seen above. You can deal with the change in one place, and your application would be able to adapt to it.

And that’s the core idea of a flexible and maintainable software design. You tame the changes, and it doesn’t hurt your application.

Factory Pattern in PHP
Introducing Car Factory Class

The Class that Makes Factory Pattern in PHP Work

We have a new class to encapsulate the changes, and we will call it CarFactory.

Car Factory Class
Car Factory Class

BookACar | The Second Release

So, developers will have to refactor BookACar class to integrate it with the CarFactory.

Factory Pattern in PHP
BookACar v2

Now, the object initialization happens in th factory class method and orderCar() delegates initialization to it which was previously tied to the orderClass() itself.

Now, if we had to add a new car or remove an older one, we know the factory class is the go-to for that purpose. The rest of the application will remain largely unaffected by that change.

We’re Not Done Yet to use the Factory Pattern in PHP

So, that’s out-of-the-box thinking and opens up new ways to think about application development. However, it is just a programming paradigm, not the factory pattern itself. The concepts we have been through will solidify the ground for the factory pattern in PHP we are about to see.

Meanwhile, here is a bigger picture of the application design thus far.

SimpleFactory Class
SimpleFactory Class

The Factory Pattern in PHP Example Complete

BookACar is now Popular!

BookACar has been the talk of the town and collaborates with an electric vehicle EV brand.

Now, the application has two menus – one for EVs and another for the existing brand.

Team A is working on the EV booking functionality of the application, and Team B is working on the existing application. You’re the lead architect now – Congratulations! But the game is not over yet!

How about the EVs? They are different from the existing brand of cars. We don’t want to place them all in one factory class. 

What if we add a new factory class for EVs?

Factory Pattern in PHP
Two Factory Classes

Well, that undoubtedly is one of the right approaches, but there’s a business requirement that we need to standardize for every car. Let’s zoom in on that next.

BookACar Purchase Policy

BookACar has the same procedure for ordering a car regardless of the type and brand. We want to keep that standard and not let any part of the application override that. The design above uses more than one factory, but the orderCar() is a standard method for both cars. 

We want to ensure that every Team in the present or future uses the same orderCar() method. In other words, we want to tie up the car creation and order in the BookACar class. 

But that would undo all the effort? Well, we will keep the creation logic in a Factory Method. The orderCar() will call this method. The orderCar() would not be concerned with the type of car, just as it was when we stripped out the creation logic last time. In more technical terms, these two methods will be decoupled.

So how to go about this problem?

BookACar Class with Abstract Factory Method

With the objective in mind, let’s modify the BookACar class. 

Abstract Factory Method
Abstract Factory Method

The Factory Method

Factory Pattern in PHP
Abstract Factory Method

An abstract method expects sub-classes to implement it the way they want to. The orderCar() is a concrete method. In our case, the two sub-classes of BookACar will implement createCar() in their way. The orderCar() will remain the same for all the sub-classes.

The Bigger Picture of the Factory Pattern in PHP

Concrete Factory Methods
Concrete Factory Methods

What’s the benefit? See, the sub-class decides the brand of the car, but the orderCar() is not concerned with what sub-class we have. It sees them all as Cars. Both methods are loosely coupled, and the design remains flexible.

Let’s Order A Car…

1. First: Let’s choose the EV brand.

Factory Pattern in PHP
Initialize Concrete Creator Class

2. Order an EV SUV.

orderCar
orderCar()

3. The orderCar() calls createCar() as follows.

Factory Pattern in PHP
createCar

4. Finally, the orderCar() performs the standard booking procedure.

returnCar
returnCar

Factory Patterin in PHP | BookACar Architecture Design Pattern

Here’s a complete picture of what we have designed thus far, and that’s what the factory design pattern is.

BookACar Design Diagram

Factory Method Design Pattern in PHP

The following code recreates the factory method design pattern in PHP for the BookACar application.

Code | Factory Method Design Pattern in PHP

<?php
class Car {
 
    private $name;
 
    function setName($name) {
        $this->name = $name;
    }
 
    function getName() {
        return $this->name;
    }
 
    function order() {
        $name = $this->getName();
        echo "Order for ${name} has been placed".PHP_EOL;
    }
 
    function purchase() {
        $name = $this->getName();
        echo "Purchase for ${name} has been made".PHP_EOL;
    }
 
    function ship() {
        $name = $this->getName();
        echo "${name} has been shipped".PHP_EOL;
    }
}
 
class HatchBack extends Car {
    function __construct() {
        $this->setName("HatchBack");
    }
}
 
class Sedan extends Car {
    function __construct() {
        $this->setName("Sedan");
    }
}
 
class SUV extends Car {
    function __construct() {
        $this->setName("SUV");
    }
}
 
class EVSUV extends Car {
    function __construct() {
        $this->setName("EVSUV");
    }
}
 
class EVSedan extends Car {
    function __construct() {
        $this->setName("EVSedan");
    }
}
 
abstract class BookACar {
 
    abstract public function createCar($type): Car;
 
    function orderCar($type) {
 
        $car = $this->createCar($type);
 
        $car->order();
        $car->purchase();
        $car->ship();
 
        return $car;
    }
 
}
 
class BookEV extends BookACar {
 
    public function createCar($type): Car {
       
        $car = null;
 
        if($type == "evsuv") {
           $car = new EVSUV();
        }
        else if($type = "evsedan") {
            $car = new EVSedan();
        }
 
        return $car;
    }
}
 
class BookNormal extends BookACar {
 
    public function createCar($type): Car {
       
        $car = null;
 
        if($type == "hatchback") {
           $car = new HatchBack();
        }
        else if($type = "sedan") {
            $car = new Sedan();
        }
        else if($type == "suv") {
            $car = new SUV();
        }
 
        return $car;
    }
}
 
 
function main() {
    $bookEV = new BookEV();
 
    $evSUV = $bookEV->orderCar("evsuv"); //Let's order an EV SUV.
 
    echo "I have bought an ".$evSUV->getName().PHP_EOL;
}
 
main();
?>

Factory Pattern in PHP : Finished Design Pattern

Order for EVSUV has been placed
Purchase for EVSUV has been made
EVSUV has been shipped
I have bought an EVSUV

Pros and Cons of the Factory Pattern in PHP

ProsCons
Loose Coupling between Creator and Product.You need to write a lot of boilerplate code and sub-classes to implement the pattern.
Flexible and maintainable design Can be difficult to comprehend sometimes.
Satisfies Single Responsibility Principle
Satisfies Open-Closed Principle

Where is Factory Pattern Used?

  • When new kinds and types of object variations are added to your application. The pattern keeps the creation code separate from the business logic. So it is flexible when you want to add more objects and their associated creator classes.
  • When you want to implement a UI framework or library. This framework adds more visual elements per the changing UI trends. So, using this pattern will allow extension without impacting the entire application.
  • You can use it for memory optimization by keeping a pool of memory-intensive objects. 

Frequently Asked Questions?

Is Factory a Static Method?

Some implementations use static factory methods, which closes the door for class inheritance. You can use a static factory method when you have one factory class with no sub-classes. For instance – the CarFactrory in the examples above can use a static createCar() method.

Is Factory a Singleton Method?

No, you can create as many objects as you need with the factory method. However, you can limit the object creation by creating a pool that’s not a part of the factory method. The Singleton pattern is a different pattern. It creates one global instance or a pool of instances for the entire application and focuses on memory optimization.

What is the Factory Pattern in PHP?

The factory design pattern is not a programming language-specific tool but a general idea about encapsulating object creation in a scenario where you can have variance in objects.

Is Factory a Function or Class?

The implementation of a factory can vary. You can implement a Factory class, but sometimes you need to loosely couple creation and business logic, and that’s where you can use abstract factory methods, just as we did above.

Using the Factory Pattern in PHP today

Phew! We covered a lot of ground covering a whole lot about factory patterns in PHP. As a quick summary, we have learned that the goal of the factory pattern is to encapsulate the object creation code from the core logic. It defines a bunch of sub-classes from a more generic class and delegates the task of object instantiation to these sub-classes.

The article uses a real-world example the factory pattern in PHP. It’s an application for booking and purchasing cars. The application collaborates with brands that offer different types of cars. The component of the application that varies is the type and brand of car – as more and more brands sign up. This scenario was ideal for implementing a factory pattern.

We have started from the bottom up from a simple and tightly coupled application code to a more flexible factory design pattern. The article also includes the complete application code for this application in PHP.

Hope you have been able to take away some value. Stay tuned for more at FuelingPHP.

Get deeper with PHP

We have many fun articles related to PHP. You can explore these to learn more about PHP.


Article Categories

Article Tags

© 2022 Confident.Systems