This is an old post from 2009. As such, it might not be relevant anymore.
I first wrote about PHP Design Patterns in the first installment, “Design Pattern I: Singleton”, and here I am again talking about, this time, the Factory pattern.
As you might have grasped from the name of the pattern its role is to produce and dispatch a product. In this case a classes. We use the Factory pattern as it is a standard way to create a class which is very similar to other classes by containing the same functions, but implemented in a different way.
I always like to use non-technical terms when explaining, and this example will be no different. Cars, there are millions of them in the world and they are produced in factories, so a good choice I think. A factory might produce one type of car one month and another type of car the next. Instead of having to go into the code and change all the new new Car_Mini() to new Car_Beetle() (for example) we can simple change a settings file and let the Factory worry about what they are doing. I’ve written the entire example below, so feel free to take a quick look, see if you can understand it then proceed to the next couple paragraphs!
We first start by defining an interface. An interface is essentially a blank canvas for us to create subclasses, but which must follow some rules. Every function the interface contains must be implemented in each of the subclasses. So, Car_Mini has each of the getWheels(), getSteeringWheel() and assemble() functions, but is also free to create some of its own functions. However, because it will be part of the factory it is unlikely to have any other public methods. Same with the Car_Beetle class.
The next two classes are implementing the interface, they don’t contain any logic in this example, the assemble() function just outputs that it has created a car. So we’ll skip over those classes. Same with the Singleton class—I covered this in the previous article.
This leads us onto the Factory class. As you can see we grab the settings class, see which car we are supposed to produce and return a new instance of that car. Now we just need to create the code to get the instance of the car, get the wheels and steering wheel and then assemble them altogether. That’s the good thing with a Factory, you can go about your business of creating cars without actually knowing which car you are making!
In this example we might be creating a Mini or a Beetle. Because both Car_Mini and Car_Beetle have their own code in the standard functions they can go about assembling their car safe in the knowledge that everything is A-Okay. If you were to run the code to the right you would receive the following output:
Mini assembled Mini assembled Beetle assembled Beetle assembled
And that’s the Factory class—returning a new instance of a class which lets the external code call standard functions safe in the knowledge that they will be run successfully.
<?php interface Car { public function getWheels(); public function getSteeringWheel(); public function assemble(); } class Car_Mini implements Car { public function getWheels() { return $this; } public function getSteeringWheel() { return $this; } public function assemble() { echo 'Mini assembled'; } } class Car_Beetle implements Car { public function getWheels() { return $this; } public function getSteeringWheel() { return $this; } public function assemble() { echo 'Beetle assembled'; } } class Singleton { private static $_Singleton; private $_repository = array(); private function __construct(){} public function getInstance() { if (is_null(self::$_Singleton)) { self::$_Singleton = new Singleton(); } return self::$_Singleton; } public function get($index) { return $this->_repository[$index]; } public function set($index, $value) { $this->_repository[$index] = $value; } } class Car_Factory { public static function create() { $settings = Singleton::getInstance(); switch ($settings->get('car')) { case 'mini' : return new Car_Mini(); break; case 'beetle' : return new Car_Beetle(); break; } } } // Produce Mini's $settings = Singleton::getInstance(); $settings->set('car', 'mini'); $car = Car_Factory::create(); $car->getWheels()->getSteeringWheel()->assemble(); $car->getWheels()->getSteeringWheel()->assemble(); // Now change to produce Beetles $settings->set('car', 'beetle'); $car = Car_Factory::create(); $car->getWheels()->getSteeringWheel()->assemble(); $car->getWheels()->getSteeringWheel()->assemble();