PHP Loose Coupling and Dependency Injection

Dependency Injection is a software design pattern that allows avoiding hard-coding dependencies and makes possible to change the dependencies both at runtime and compile time. Always inject, (pass object as an argument) dependencies into the constructor. Creating instances within the constructor creates a tight coupling between the two classes.

Version 1 is documented, extendable and testable, as the MyService class does not care how the Config object was made, and it can be interchanged with any instance of IConfig and it can be mocked. If we add a new parameter to Config’s constructor, we then have to modify every class where we create a Config object.

Version 2 is highly coupled, and not easily testable.

Version 1

class MyService {
    public function __construct(IConfig $config){
        $this->config = $config;  // 
    } 
}

// If any dependencies change or object is not created, the problems are not brought to the service class object.
$deps = [1,2];
$config = new Config($deps);
$service = new MyService($config);

// ** NOT
$service = new MyService(new Config($deps));

The MyService class does not necessarily need to know about any IConfig implementation, it should be confined to its own functionality only. So writing any Config class code in MyService class doesn’t make it modular. This also defeats the Single responsibility principle.

Version 1 is now:
  • Modular: The Dependency Injection helps create completely self-sufficient classes or modules
  • Testable: It helps write testable code easily
  • Maintainable: Since each class becomes modular, it becomes easier to manage it

Version 2

Now you have just inherited any problems the Config obj might have

class MyService {
    public function __construct(){
        $this->config = new Config();
    } 
}

Using Factories

If there are NO dependencies required, it can be helpful to use a Factory.

class ServiceFactory
{
    private $storage = [];

    public function create( $name )
    {
        if ( false === array_key_exists( $name, $this->storage ))
        {
            $instance = new $name;
            $this->storage[$name] = $instance;
        }

        return $this->storage[$name];
    }

}