A Factory method pattern is a method for object creation via a dedicated object that handles all the business logic based on a specific input. Multiple classes exist with the same interface or base class. In the example below the transport object is created by the goBy() factory method of the transportFactory class.

class Transport {
    public function getCosts(){
       return 20;
     }
}

class Train extends Transport {
    /**
     * return train costs
     * @return int
     */
    public function getCosts() {
        return 100;
    }
}

class Plane extends Transport {

     /**
     * return plane costs
     * @return int
     */
    public function getCosts(){
        return 200;
    }
}

class TransportFactory {

    /**
     * Factory method
     * @param string $vehicle
     * @return \Plane|\Train
     */
    public function goBy($vehicle) {
        switch ($vehicle) {
            case "train":
                return new Train;
                break;
            case "plane":
                return new Plane;
                break;
        }
    }
}

$transportFactory = new TransportFactory();
$transport = $transportFactory->goBy('train');
$costs = $transport->getCosts(); // outputs 100

On a practical level, in the age of intelligent IDE’s (integrated development environment) what method information does the IDE return? Netbeans and PHPStorm both allow you to choose between available methods each with their own docblocks.

In the example above the base class Transport can be instantiated as well. In a special type of the factory pattern, this class is either abstract or the subclasses implement an interface. This variation is called the abstract factory pattern.

abstract class Transport {
    abstract public function getCosts();
}

In another variation there is nothing to keep the factory method to become static:

class TransportFactory {

    public static function goBy($vehicle) {
        switch ($vehicle) {
            case "train":
                return new Train;
                break;
            case "plane":
                return new Plane;
                break;
        }
    }
}
$transport = TransportFactory::goBy('plane');

What of factory implementations in some modern frameworks, for example in database instantiations? In Zend Framework I the factory method is very much static:

class Zend_Db {
    public static function factory($adapterName) {
        $adapterName = 'Zend_Db_Adapter_' . $adapterName;
        if (!class_exists($adapterName)) {
            require_once 'Zend/Loader.php';
            Zend_Loader::loadClass($adapterName);
        }
        return new $adapterName();
    }
}

$db = Zend_Db::factory('PDO_MYSQL');

Unfortunately the class name is dynamically generated which does not help debugging the application.

In Zend Framework II it is all about services:

class AdapterServiceFactory implements FactoryInterface {
    public function createService(ServiceLocatorInterface $serviceLocator) {
        $config = $serviceLocator->get('Config');
        return new Adapter($config['db']);
    }
}

 


The actual factory creating the adapter based on the configuration is the createPlatform method in the Adapter class. The adapter then called as an service through the service manager:

return array(
    'service_manager' => array(
        'factories' => array(
            'dbAdapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
        ),
    ),
    'db' => array(
        'driver' => 'pdo',
        'dsn' => 'mysql:dbname=db;host=localhost',
        'username' => 'admin',
        'password' => '123',
    ),
);

In ZF2 factories are also de recommended way to handle dependency injection. So instead of calling a controller directly the controller is called via a factory method. Inside this method the controller class is returned with all the required class dependencies as arguments.

Laravel has a ConnectionFactory class with a createConnection factory method:

protected function createConnection($driver, PDO $connection, $database) {	
		switch ($driver)
		{
			case 'mysql':
				return new MySqlConnection($connection, $database, $prefix, $config);
			case 'pgsql':
				return new PostgresConnection($connection, $database, $prefix, $config);
			case 'sqlite':
				return new SQLiteConnection($connection, $database, $prefix, $config);
			case 'sqlsrv':
				return new SqlServerConnection($connection, $database, $prefix, $config);
		}
		throw new \InvalidArgumentException("Unsupported driver [$driver]");
	}

In Symfony, services can be created just as in ZF2. The factory method will be called statically.

Sources

* https://en.wikipedia.org/wiki/Factory_method_pattern
* https://sourcemaking.com/design_patterns/factory_method
* http://stackoverflow.com/questions/4719822/factory-abstract-factory-confusion
* http://coderoncode.com/2014/01/19/design-patterns-php-factories.html
* http://symfony.com/doc/current/components/dependency_injection/factories.html

Advertisements