Backend DevelopmentDesign PatternsWeb Development

Creating Classes With PHP Factory, Abstract Factory, Simple and Static Factory Patterns

php factory pattern

Factories act as a way to create a new instance of specific class, in another way instead of handling the creation of the class by the client code some classes will be in charge of that and handles the creation process, all you have to do is to call that factory.

 

 

There are four types of factories:

  • Factory Method
  • Abstract Factory Method
  • Simple Factory
  • Static Factory

 

First Pattern: The Factory Method

The Factory pattern is one of the commonly used design patterns.

In it’s normal form is a class that can be instantiated and have a method that takes some parameters and creates a new instance based on these parameters, to understand how this is work let’s show an example:

 

Imagine that we have an interface for Geometrical shapes like Rectangle, Triangle, Circle, etc and have only one method draw that draws a shape according to position like this:

<?php

interface Shape{
    public function draw();
}

class Position{
    public $x;
    public $y;
}

 

Now let’s create a specific shape from this interface for example Rectangle as shown below:

class Rectangle implements Shape{
    private $position;
    
    public function __construct(Position $pos) {
        $this->position = $pos;
    }
    
    public function draw(){
        echo "Drawing a rectangle with position (".$this->position->x .",".$this->position->y.")<br/>";
    }
}

As shown in the code above we implemented the Shape interface and typehint the constructor with the Position parameter through using dependency injection and finally implemented the concrete draw() method.

 

Now to create an instance of the class we can do something like this:

<?php
$pos = new Position;
$pos->x = 34;
$pos->y = 55;

$rectangle = new Rectangle($pos);

$rectangle->draw();

 

But we can create a new instance in another way using the Factory method pattern as shown below:

<?php
class ShapeFactory{
    public function create($class, $position)
    {
        return new $class($position);
    }
}

$pos = new Position;
$pos->x = 34;
$pos->y = 55;
$shape = new ShapeFactory;
$rect = $shape->create("Rectangle", $pos);
var_dump($rect);

As shown above we created a new shape factory class and has a method that takes the class name as a string and returns a new instance of that class. This method is called the creator.

 

Now you can create Circle and Triangle classes the same way as Rectangle as shown in the following code:

<?php
class Circle implements Shape{
    private $position;
    
    public function __construct(Position $pos) {
        $this->position = $pos;
    }
    
    public function draw(){
        echo "Drawing a circle with position (".$this->position->x .",".$this->position->y.")<br/>";
    }
}

class Triangle implements Shape{
    private $position;
    
    public function __construct(Position $pos) {
        $this->position = $pos;
    }
    
    public function draw(){
        echo "Drawing a triangle with position (".$this->position->x .",".$this->position->y.")<br/>";
    }
}


// client code
$pos = new Position;

$shape = new ShapeFactory;

$pos->x = 100;
$pos->y = 20;

// create circle instance
$circle = $shape->create("Circle", $pos);
var_dump($circle);
$circle->draw();

$pos->x = 110;
$pos->y = 50;

// create triangle instance
$triangle = $shape->create("Triangle", $pos);
var_dump($triangle);
$triangle->draw();


As you see the advantage of this approach is that you don’t have to remember each class and how it’s instantiated, just give the class name to the creator and the creator gives you the instance.

 

Second Pattern: The Abstract Factory Method

The abstract factory method is the as the factory method except that in this case instead of just having one class, you have a series of related or dependent objects and they share a common interface and you need an easy way to create objects for each concrete class.

 

Let’s imagine that we need to format text in two ways, json and html so we need to create a concrete abstract class that will represent our concrete base implementation as follows:

<?php

// Concrete Classes
abstract class Text
{
    private $text;
    
    public function __construct(string $text) {
        $this->text = $text;
    }
}

 

Next we have to add the different implementations for that class as shown below:

<?php

// Concrete implementations
class JsonText extends Text
{
    public function __construct(string $text) {
        parent::__construct($text);
        return "{" . $text . "}";
    }
}

class HtmlText extends Text
{
    public function __construct(string $text) {
        parent::__construct($text);
        return "<html><head></head><body>{$text}</body></html>";
    }
}

As shown above each class extends from the abstract Text class and provides it’s own implementation.

Now To create the factory using this approach you have to define the base abstract factory and it’s child implementations like this:

// Abstract Factoy Class
abstract class TextFactory
{
    abstract public function createText(string $text) : Text;
}

// Different implementions of factory 
class JsonFactory extends TextFactory
{
    public function createText(string $text) : Text 
    {
        return new JsonText($text);
    }
}

class HtmlFactory extends TextFactory
{
    public function createText(string $text) : Text 
    {
        return new HtmlText($text);
    }
}

So as you see in the code above for each concrete implementation [classX] we define concrete factory (factoryX) and each factory responsible for only creating instance of his class.

<?php

$factory = new HtmlFactory();
var_dump($factory->createText("<h2>This is sample html content</h2>"));

$factory = new JsonFactory();
var_dump($factory->createText("'name': 'Test','description': 'sample json content', 'version': '1.0.0'"));
echo "</pre>";

This approach in some cases not considered a real design pattern because it violates the principle of dependency injection, instead of using the classes through dependency injection, it calls the classes directly in the code and this considers a bad practice in OOP.

 

Third Pattern: The Static Factory Method

This pattern like the abstract factory method is used to create series of related or dependent objects. The difference between this and the abstract factory pattern is that the static factory pattern uses just one static method to create all types of objects it can create.

 

A good practice when creating the static factory class it to declare it as final to disable other classes from overriding it, also the factory method must be static and return the class instance based on some sort of condition as shown in the following example.

interface FormatterInterface{

}

class FormatString implements FormatterInterface{
    public function __construct($data)
    {
        return <<<BEGIN
$data
BEGIN;
    }
}

class FormatNumber implements FormatterInterface{
    public function __construct($data)
    {
        return number_format($data, 2);
    }
}

final class StaticFactory{
    public static function factory(string $type, $data) : FormatterInterface
    {
        if($type == 'number') {
            return new FormatNumber($data);
        }

        if($type == 'string') {
            return new FormatString($data);
        }

        throw new \InvalidArgumentException('Unknown Format given');
    }
}

// Client
echo "<pre>";
echo "<h2>Testing create number formatter</h2>";
var_dump(StaticFactory::factory('number', 67889));

From the code above we created just one factory class and it contains just one factory static method that takes a argument $type, then we do a simple if statement to return the valid class instance based on that argument.

Fourth Pattern: The Simple Factory Method

The simple factory method differs from the static factory because it is not static. In this pattern instead of having one static factory method, you have a factory method for each class you want to initialize. For this reason the simple pattern is usually preferred over the static pattern.

class Bicycle
{
    public function driveTo(string $destination){

    }
}

class Car
{
    public function driveTo(string $destination){

    }
}

// The factory
class SimpleFactory
{
    public function createBicycle() : Bicycle
    {
        return new Bicycle();
    }

    public function createCar() : Car
    {
        return new Car();
    }
}

// Client
$bicycle = (new SimpleFactory())->createBicycle();
$car = (new SimpleFactory())->createCar();
echo "<pre>";
var_dump($bicycle);
var_dump($car);
echo "</pre>";

 

As you see we declared two methods for each class and each method responsible for creating instances.

public function createBicycle() : Bicycle
    {
        return new Bicycle();
    }

    public function createCar() : Car
    {
        return new Car();
    }

 

 

Conclusion

In this tutorial we covered the four types of factory pattern and describe them with simple examples. Factories is a good alternative for class instance creation as it provides a standard way of creating objects without knowing the internals of classes.

5 1 vote
Article Rating

What's your reaction?

Excited
0
Happy
2
Not Sure
2
Confused
4

You may also like

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
matt
matt
4 years ago

Thank you so much for this content.