Best Practices · PHP

The Buzzword called ‘Dependency Injection’

The term ‘Dependency Injection’ has become one of the trending buzzwords in the PHP community lately. The concept around ‘Dependency Injection’ is actually a good one, but I just feel it’s being oversold under this fancy name. This post is about helping developers realize how they might have already been using this concept in their code without ever calling it ‘Dependency Injection’.

Let’s dissect this term a bit and see what each of the words mean. The word ‘injection’ means simply to insert something. Then there is this word ‘dependency’ – which means ‘something that is needed’. To wrap it up, it means ‘inserting something that is needed’ in your code.

Let’s see a simple example to see what I mean. Imagine a class called Customer which has a method named getOrders(), it might look like this:

<?php 

class Customer
{
    public function getOrders()
    {
        $db = new MySqlClass();
        return $db->getAllOrdersByThisCustomer();
    }
}

Inside the getOrders() method, we are creating a new MySqlClass object and calling its method to get all orders by this customer. Don’t pay too much attention to the technical correctness of the code, focus on the concept. A MySqlClass object is being created to get the orders for this customer from the database. This means that the Customer class ‘depends’ on MySqlClass for getting the orders from the database. Without the MySqlClass, the Customer class cannot get the orders from the database.

Let’s extend this example further, and think about all the other methods that might be needed in the Customer class:

<?php 

class Customer
{
    public function getOrders()
    {
        $db = new MySqlClass();
        return $db->getAllOrdersByThisCustomer();
    }

    public function getBillingAddress()
    {
        $db = new MySqlClass();
        return $db->getBillingAddressForThisCustomer();
    }

    public function getShippingAddress()
    {
        $db = new MySqlClass();
        return $db->getShippingAddressForThisCustomer();
    }
}

We are instantiating the MySqlClass in each of the methods. Of course, being the good programmer that you are, you would right away spot this duplication of code and think of ways to eliminate this duplication. You can avoid this duplication by passing the MySqlClass object as an argument to each of the methods like this:

<?php 

class Customer
{
    public function getOrders(MySqlClass $db)
    {
        return $db->getAllOrdersByThisCustomer();
    }

    public function getBillingAddress(MySqlClass $db)
    {
        return $db->getBillingAddressForThisCustomer();
    }

    public function getShippingAddress(MySqlClass $db)
    {
        return $db->getShippingAddressForThisCustomer();
    }
}

So essentially, we are now ‘injecting’ the MySqlClass object that the Customer object ‘depends’ upon as an argument in each of the methods. This is what ‘Dependency Insertion’ is all about. You read that right. That’s really all there is to it. This is something that any decent programmer has been doing forever but it took some fancy buzzword to make this very simple idea into a seemingly complicated one. Technically speaking, when you pass or ‘inject’ a dependency in the method, this is known as ‘Method Injection’.

Let’s build on this idea and improve the code further. Instead of passing the MySqlClass in every method, we could just pass the MySqlClass object as an argument to the constructor, making the code even simpler:

<?php

class Customer
{
    private $db;

    function __construct(MySqlClass $databaseObject)
    {
        $this->db = $databaseObject;
    }

    public function getOrders()
    {
        return $this->db->getAllOrdersByThisCustomer();
    }

    public function getBillingAddress()
    {
        return $this->db->getBillingAddressForThisCustomer();
    }

    public function getShippingAddress()
    {
        return $this->db->getShippingAddressForThisCustomer();
    }
}

The Customer class now takes its dependency as an argument via the constructor and stores it in a private member variable, and uses it whenever needed by any of its methods. This kind of dependency injection is known as ‘Constructor Injection’.

When to use ‘Method Injection’ vs ‘Constructor Injection’

When injecting dependencies, one might ask when to use method injection and when to use constructor injection. The answer is very simple and one that makes sense: Use Constructor injection when injecting dependencies which are key to the creation of the object. A good example is the Car class. A Car might work without a high end music system installed in it but it wouldn’t run without an Engine. This means that an ‘Engine’ object is something that you would want to inject in the constructor of the Car object since without an Engine, the whole Car object isn’t worth much. On the other hand, the ‘MusicSystem’ object is something you can pass as a method e.g. a method called addMusicSystem(MusicSystem myAwesomeMusicSystem) which lets you add a music system to your Car.

Why Bother?

That’s a good question. Why would one want to insert the dependencies like that? The most obvious benefit is that we eliminate any repetition of code. However, there are a couple of not so obvious but more interesting features of the Customer class that one might think about, which are discussed below.

1. Testability

Let’s start with Testability. When you are writing Unit tests, you would want to test the functionality of your Customer class without worrying about any other classes that the Customer class depends upon. The good news is, with our latest iteration of the Customer class, we could just insert a mock object for the MySqlClass in the constructor and wouldn’t have to worry about the dependencies that the methods of the Customer class have on the MySqlClass.

Here is an example PHPUnit test that shows what I’m talking about:

<?php

class CustomerTest extends PHPUnit_Framework_TestCase
{
    public function testGetAllOrdersByThisCustomer()
    {
        // we can easily pass mock objects now
        $MySqlClassMock = $this->getMock('MySqlClass');
        $customer = new Customer($MySqlClassMock);
        $this->assertEquals(10, count($customer->getOrders()));
    }
}

If we only had the first version of the Customer class that we built above, we’d have no way to mock the MySqlClass.

2. Flexibility

Another feature of the latest version of the Customer class is that it offers much more flexibility in terms of architecture. For example, imagine if the company you are working for decides to change the database from MySQL to PostgreSQL. In that case, you wouldn’t have to change much inside your actual code. All you would have to do is pass the PostgreSQLClass reference:

<?php

class Customer
{
    private $db;

    function __construct(PostgreSqlClass $databaseObject)
    {
        $this->db = $databaseObject;
    }

    //...
}

Although it sounds fine and dandy, with this approach, you would have to make sure that the PostgreSQLClass also has the same methods as the ones you were using for MySqlClass otherwise you would have to change those method calls as well! This certainly isn’t very convenient. Wouldn’t it be nice if we could somehow make sure that no matter what kind of object is passed to the Customer, it should provide all the methods that are needed by the Customer class. Enter the Interfaces! So, we can go one level up and update our Customer class to instead accept an interface in its constructor:

<?php

class Customer
{
    private $db;

    function __construct(DatabaseInterface $databaseObject)
    {
        $this->db = $databaseObject;
    }

    //...

}

By passing an interface as an argument, we enable the Customer class to have any kind of object that implements the DatabaseInterface. This concept is known as ‘Programming to an Interface’ and helps you write flexible code which is easy to extend. The code for the DatabaseInterface is shown below:

<?php

interface DatabaseInterface {

    public function getAllOrdersByThisCustomer();
    public function getBillingAddressForThisCustomer();
    public function getShippingAddressForThisCustomer();

}

We now change our concrete database classes MySqlClass and PostgreSQLClass to implement the DatabaseInterface:

<?php

class MySqlClass implements DatabaseInterface {

    public function getAllOrdersByThisCustomer()
    {
        // MySql specific implementation here
    }

    public function getBillingAddressForThisCustomer()
    {
        // MySql specific implementation here
    }

    public function getShippingAddressForThisCustomer()
    {
        // MySql specific implementation here
    }
}

class PostgreSqlClass implements DatabaseInterface {

    public function getAllOrdersByThisCustomer()
    {
        // PostgreSql specific implementation here
    }

    public function getBillingAddressForThisCustomer()
    {
        // PostgreSql specific implementation here
    }

    public function getShippingAddressForThisCustomer()
    {
        // PostgreSql specific implementation here
    }
}

Look at the code above and try to think about why we’ve taken the pain of doing all this. This has certainly increased the number of lines of code. At the same time though, it has provided us with greater flexibility. These kinds of design strategies might be overkill in tiny programs but come in very handy in real world projects which grow with time and change with changing demands of business.

The Customer class is quite flexible now. Wherever we create our Customer, we have the flexibility of using whatever database provider we want to use without changing anything in the Customer class itself:

<?php

// both these implement DatabaseInterface
$mysqlObject = new MySQLClass();
$postgresqlObject = new PostgreSQLClass();

// works!
$customer = new Customer($mysqlObject);

// works as well!
$customer = new Customer($postgresqlObject);

You don’t to worry much if you decide to change your database provider yet again in the future or decide to use multiple databases at the same time. All our Customer class needs is an object that adheres to the DatabaseInterface.

To conclude, I hope this post provided you with some valuable insight and you learned that the concept of ‘Dependency Injection’ is relatively straight forward and not as complicated as it sounds. Besides that, I hope you also saw some concepts behind writing code that is easy to extend and test.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s