29.3 Factory
Factory is a design pattern aimed at decoupling the instantiation of your objects from the application code that uses them. For example, you may want to use different kinds of objects depending on the situation. If you have two rendering classes, HtmlRenderer and WmlRenderer, and want your application to transparently use the right one depending on what kind of client is connected, you can easily do that using the Factory design pattern.
There are many different variants of the Factory design pattern. In Figure 29.2 we pick a simple one, which simply uses a global function.
Figure 29.2 Factory pattern.
The Factory method receives no arguments, but in many situations you may wish to pass information to the Factory that will help it determine what kind of object should be instantiated. Nothing in the Factory pattern prevents you from passing arguments to the constructor.
A popular case for using factory methods is implementing an unserializera piece of code that takes a two-dimensional, serialized stream and turns it into objects. How do we write general-purpose code that will be able to instantiate any type of object that may appear in the stream? What if you want to specify different arguments to the constructor, depending on the type of object you're instantiating? Listing 29.2 contains an implementation.
Listing 29.2 Registered classes with the Factory pattern
<?php
class Factory
{
private $registeredClasses = array();
static private $instance = NULL;
private function __construct() {}
static function getInstance()
{
if(self::$instance == NULL)
{
self::$instance = new Factory();
}
return self::$instance;
}
function registerClass($id, $creator_func)
{
$this->registeredClasses[$id] = $creator_func;
}
function createObject($id, $args)
{
if(!isset($this->registeredClasses[$id]))
{
return(NULL);
}
return($this->registeredClasses[$id]($args));
}
}
class MyClass
{
private $created;
public function __construct()
{
$created = time();
}
public function getCreated()
{
return($this->created);
}
}
function MyClassCreator()
{
return(new MyClass());
}
$factory = Factory::getInstance();
$factory->registerClass(1234, "MyClassCreator");
$instance = $factory->createObject(1234, array());
?>
Those of you who are familiar with the bits and bytes of PHP's syntax know that there's a simpler way of doing it. Listing 29.2 demonstrates a more object-oriented way to solve the problem, as it is done in other languages. It also allows for flexibility should you wish to implement additional logic in the creator (possibly sending some information to the constructor). In practice, it's accurate to say that PHP has built-in support for factory methods, utilized by simply writing $object = new $classname.