Instantiating Objects From Factory Classes in PHP
Auto instantiating objects created by factory classes.
By. Jacob
Edited: 2020-07-27 11:05
While using factories in PHP to build objects from lots of dependencies, you might be wondering how to best instantiate the object from your composition root (often your index.php file).
Creating the object from your constructor class does not work, so you will need to approach the problem differently.
I propose the following syntax:
$http_client = (new my_project\lib\factories\http_client_factory())->build();
The problem
While instantiating factory classes with the new keyword, you find that you can not return the final object directly from your constructor class, forcing you to first call a create() or build() method from your compositioning root.
You could load the object into a public property of the factory, but this would be dirty, as you would need to access your object through this property whenever using it. You could also use a singleton pattern for your factory, but people tend to dislike singletons.
Having to re-assign the object to a external variable in your composition root is also not very desirable, so what do you do? The following clearly does not work:
$http_client = new myProject\lib\factories\http_client_factory()->build();
And you probably also want to avoid this:
$factory_product = new myProject\lib\factories\http_client_factory();
$http_client = $factory_product->build();
However, the problem can be solved just by wrapping the new statement in some parentheses, reducing our work to this nice one-liner:
$http_client = (new myProject\lib\factories\http_client_factory())->build();
All you need to do in your factory class, is then to include your dependencies in the public build() method. Of course you should use Dependency Injection inside the factory itself.
A simple factory class
Factories are useful when you got an object that is made up of several other objects (dependencies), and you want to simplify the instantiation of the object. It also avoids having to memorize all the dependencies a object needs in order to be instantiated.
It is generally considered a bad practice to instantiate objects inside other objects using the new keyword (tightly coupled), but there is a exception for this, and that is within factory classes (loosely coupled).
A basic example of a factory class looks like this:
class file_handler_factory
{
public static function build()
{
$superglobals = new \doorkeeper\lib\superglobals\superglobals();
$helpers = new \doorkeeper\lib\php_helpers\php_helpers();
$file_types = new \doorkeeper\lib\file_handler\file_types();
return new \doorkeeper\lib\file_handler\file_handler($helpers, $superglobals, $file_types);
}
}
The above is actually taken from a real project I am working on, and while still undergoing changes, it is a useful example of how to write a factory.
You could also seperate each dependency into its own method, but I personally found that this will just result in spaghetti code. For example:
class file_handler_factory
{
public function build() {
$this->create_superglobals();
$this->create_helpers();
return $this->create_file_handler();
}
private function create_superglobals()
{
$this->superglobals = new \doorkeeper\lib\superglobals\superglobals();
}
private function create_helpers()
{
$this->helpers = new \doorkeeper\lib\php_helpers\php_helpers();
}
private function create_file_handler()
{
$file_types = new \doorkeeper\lib\file_handler\file_types();
return new \doorkeeper\lib\file_handler\file_handler($this->helpers, $this->superglobals, $file_types);
}
}
Tell us what you think: