Dependency Injection, Services and Containers (DIC) – part 3

Aaaand we are on part 3, and you still don’t know what the hell am I talking about. OK. Lets explain a little more, and we’ll continue on the types of injection and Service Locators and DI Containers.

The Dependency Injection is a technique that follows the Inversion of Control. If you wish to follow that click here. So just to make things clearly lets get the Wikipedia definition about IoC:

A design in which custom-written portions of a computer program receive the flow of control from a generic, reusable library.

A software architecture with this design inverts control as compared of traditional procedural programming.

So if it doesn’t sound that clearer, I’ll try to make it crystal:

With inversion of control, the custom code calls a library to perform a task, without caring about the dependencies. And that best practice I was explaining in the previous two parts of this post.

Dependency Injection Series

But lets me point some other things that they are defined with the term Dependency Injection. The first two definitions are tight and loose coupling. Let me show the two again, and why the Dependency injection pattern is so popular.

DI has 3 general ways to be executed:

  • Constructor injection
  • Setter injection
  • Interface injection

Tight & Loose coupling. Constructor injection

Let say that we have a User object, that after the registration we need to send a mail to confirm that registration. The examples are simplified.

namespace App\Models;

use App\Lib\Mailer;

class User extends abstractModel
{
    private $mailer;
    private $userData;

    public function __construct($userData)
    {
        $this->userData = $userData;
        $this->mailer = new Mailer();
    }

    public function save()
    {
        // saves the user to the DB and sends a mail
    }
}

// The user has submitted it's data via a form

$user = new User($formInput);
$user->save();

As stated in the previous parts … What happens in we decide to change the Mailer library? You can’t, at least not that easily. That’s the idea of tight coupling. One cannot exists without the other (coupling), tight (not that amenable to modifications). And the first type of injection and the loose coupling are demonstrated as in previous posts, and here:

interface MailInterface
{
    public function send();
}

class Mailer implements MailInterface
{
    public function send()
    {
        // ...
    }
}

class User
{
    private $mailer;
    private $userData;

    public function __construct($userData, MailInterface $mailer)
    {
        $this->userData = $userData;
        $this->mailer   = $mailer;
    }

    public function save()
    {
        // saves the user to the DB and sends a mail
    }
}

// The user has submitted it's data via a form
$mail = new Mailer();
$user = new User($formInput, $mail);
$user->save();

So with the example above, the User class doesn’t care what the Mailer object does. The only thing that the User object needs to know, is that its method save() must send a mail. And with the interface we secure that the Mailer object can send the mail. And in the next version of the framework we can easily change the service.

Here is the first type of DI – the constructor injection. We pass the dependencies via the object’s constructor.

Setter injection

The second type is the setter injection. And all the best practices shows that we need to use loose coupling so with every example I will try to comply to that principle.

interface MailInterface
{
    public function send();
}

class Mailer implements MailInterface
{
    public function send()
    {
        // ...
    }
}

class User
{
    private $mailer;
    private $userData;

    public function __construct($userData)
    {
        $this->userData = $userData;
    }

    public function save(MailerInterface $mailer)
    {
        $this->mailer = $mailer;
        // saves the user to the DB and sends a mail
    }
}

// The user has submitted it's data via a form
$mail = new Mailer();
$user = new User($formInput);
$user->save($mail);

Note the little change here … In the previous example we’ve injected the Mailer object with the instantiation of the User object. And here with the setter injection we inject the Mailer object when we need it.

So here the logical question is: “So what makes setter injection special or better or worse than constructor injection?” Well … For me is a personal preference. If you have to inject 50 dependencies setter injection is the better option (of course if you inject 50 dependencies in an object – you’ve clearly done something wrong). So Martin Fowler states that:

Another advantage with constructor initialisation is that it allows you to clearly hide any fields that are immutable by simply not providing a setter

Well that’s true, but with setter injection you can do something like this:

class User
{
    private $mailer = null;
    private $userData;

    public function __construct($userData)
    {
        $this->userData = $userData;
    }

    public function setMailer(MailerInterface $mailer)
    {
        if(is_null($this->mailer)) {
            $this->mailer = $mailer;
        }
    }
}

This implementation makes the mailer immutable since can only be injected if the $mailer is null. But sometimes this has a downside, because you’ll need more than one instance of a given object. Generally with DI you need objects that are immutable. Still – sometimes has its benefits, sometimes not. As the person developing that technique and knowing what is going on behind the scenes in your application, you are the one deciding what and how to be implemented.

M.Flower states also:

Constructors with parameters give a clear statement of what it means to create a valid object in an obvious place

And sometimes it’s easy for the second programmer of your team, when he / she looks at your DI implementation and sees the constructor parameters to understand with one look what is getting injected. And with setter injection is hard to find which dependency is injected and when.

Interface injection

Generally this type of injection is like setter, and if you try to locate it somewhere else most of the programmers doesn’t exclude it like a variety of the DI. Do you remember the Best practices? Yeah … That’s why. Usually when you do an injection the object that you’re injecting is implementing an interface. One of the benefits here is that the dependency is pretty easy to spot, and the interface acts like a contract telling your object what it needs to implement for that particular injection to work.

class Request
{

}
class Response
{

}
interface RequestInterface
{
    public function injectRequest(Request $request);
}

interface ResponseInterface
{
    public function injectResponse(Response $response);
}
 
class Router implements RequestInterface, ResponseInterface
{
    private $request;
    private $response;
 
    public function injectRequest(Request $request)
    {
        $this->request = $request;
    }
 
    public function injectResponse(Response $response)
    {
        $this->response = $response;
    }
}

Difference between the setter and interface injection is obvious. You typecast the interface and the magic happens. The specific thing here is that my Router class implements two interfaces that the Request and Response object are dependant upon.

There is a second way with interface injection, that I must point out

class Request implements RequestInterface
{

}
class Response implements ResponseInterface
{

}
interface RequestInterface
{
    public function injectRequest(Request $request);
}

interface ResponseInterface
{
    public function injectResponse(Response $response);
}
 
class Router
{
    private $request;
    private $response;
 
    public function injectRequest(RequestInterface $request)
    {
        $this->request = $request;
    }
 
    public function injectResponse(ResponseInterface $response)
    {
        $this->response = $response;
    }
}

You can see the main difference here. The Router class asks for the Request and Response object, and they are typecasted via the corresponding interfaces, and that’s the other way with interface injection when the Router waits for objects that implements the interfaces.

There is no wrong or right here … Just use that one that you find suitable. Take note here, don’t mix the patterns when you are constructing your application because it’s a horror for bug tracking, testing and scaling.

Traits

The last and final IoC technique in PHP is using traits.

As stated in this post – Trait is a mechanism for code reuse. It is similar to a class, but cannot be instantiated on its own. You can use it in a class with the keyword “use”. And in short: Trait is a group of methods that you want to include within another class or classes.

With traits your code becomes more readable and re-usable. In traits we hold snippets of code that we want to reuse so it becomes something like this:

I’m creating an interface that will inject the Request object

interface RequestInterface
{
    public function injectRequest(Request $request);
}

Then write a trait with the inject method which can be re-used by every class that need the dependency

trait RequestInjector
{
    public function injectRequest(Request $request)
    {
        $this->request = $request;
    }
}

Use both the interface and the trait for the injection

class Router implements RequestInterface
{
    use RequestInjector;
}
 
$router = new Router();
$router->injectRequest(new Request());

On the next part – Containers and Service Locators

Advertisements

2 thoughts on “Dependency Injection, Services and Containers (DIC) – part 3

Give your opinion

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