Dependency Injection

Dependency Injection in PHP

What is Dependency Injection?

A Dependency is an object that can be used. An Injection is the passing of a dependency (object) to a dependent object that would use it. Eventually, Dependency Injection means giving the object all the dependencies (needed objects).

For example, a User object uses a Mailer object to send welcome email. In this example the Mailer object is a dependency for the User object. We can ascribe this dependency to classes as well. Now, we should pass Mailer instance to User object instead of creating new instance of Mailer in the User body.

How Dependency Injection can be useful?

Modularity

No new instances. No direct (hard) dependency. Classes and packages can be implemented stand-alone.

Teamwork

Developers don’t wait for implementation of the dependencies. The use the Interfaces instead and save a lot of time.

SOLID principles

Single Responsibility Principle

In object-oriented programming, the single responsibility principle states that every class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility.

Single responsibility principle, Wikipedia

Open/Close Principle

In object-oriented programming, the open/closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”; that is, such an entity can allow its behavior to be extended without modifying its source code. This is especially valuable in a production environment, where changes to source code may necessitate code reviews, unit tests, and other such procedures to qualify it for use in a product: code obeying the principle doesn’t change when it is extended, and therefore needs no such effort.

Open/closed principle, Wikipedia

Dependency inversion principle

In object-oriented programming, the dependency inversion principle refers to a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are inverted (i.e. reversed), thus rendering high-level modules independent of the low-level module implementation details. The principle states:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

B. Abstractions should not depend on details. Details should depend on abstractions.

Standard Coding

I can’t believe someone dislike Dependency Injection. If there is, no problem! It’s a standard and you have to follow it whether or not you like it 😉

When all people follows standards, they will be more understandable.

Hard Dependencies

Hard dependencies will be implemented when the programmer isn’t familiar with Dependency Injection pattern. let me show you with an example.

Consider Mailer class:

class Mailer {

    public $email;

    function setEmail($email) {
        $this->email = $email;
    }

    function send($message) {
        // Sending implementation...
    }

}

And the User class:

class User {
    function register($email) {
        // Register user in database...
        $mailer = new Mailer();
        $mailer->setEmail($mail);
        $mailer->send("Welcome to our website!");
    }
}

User instances are so-called dependent and Mailer instances are dependencies.

Soft Dependencies

Soft Dependencies will be implemented when the programmer uses Dependency Injection pattern.

All you should do is avoiding declare new instances in class body and getting them via methods instead.

Let’s re-declare  the User class:

class User {

    function register(Mailer $mailer, $email) {
        // Register user in database...
        $mailer->setEmail($email);
        $mailer->send("Welcome to our website!");
    }

}

There are some benefits when you implement User this way. Let’s introduce the better implementations. I’ll talk over the benefits.

Design based on Dependency Injection

In Dependency Injection based design, you must use soft dependencies to implement classes.

Let’s implement User class better:

class User {

    public $mailer;

    function register($email) {
        // Register user in database...
        $this->mailer->setEmail($email);
        $this->mailer->send("Welcome to our website!");
    }

    function setMailer(Mailer $mailer) {
        $this->mailer = $mailer;
    }

}

Now other methods in User class can use Mailer instance. There is dedicated method to inject Mailer instance into User instances.

Now let’s do it even better!

Mailer Interface:

interface MailerInterface {
    function send($message);
}

Mailer class:

class Mailer implements MailerInterface {

    public $email;

    function setEmail($email) {
        $this->email = $email;
    }

    function send($message) {
        // Sending implementation...
    }

}

User class:

class User {

    public $mailer;

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

    function register($email) {
        // Register user in database...
        $this->mailer->setEmail($email);
        $this->mailer->send("Welcome to our website!");
    }

}

Now I want to check the benefits in the mentioned example.

Modularity

User and Mailer classes are completely separate and stand-alone. If you make new User object, there won’t be an error even if there wasn’t any Mailer class.

Open/Close

No one has to modify Mailer class. Isn’t Mailer class qualified for your project? No problem at all. Thanks to Dependency Injection, you don’t have to use Mailer class. You may design your own mailer and inject it into User class as long as it implements MailerInterface (that just force you have send() method).

See? It’s really nice aspect. I love it. Now you may understand “soft dependency” term so better.

Teamwork

Does User class implementer (programmer) has to wait for Mailer class implementer? Of course not! User class uses MailerInterface (which takes some minutes to be implemented) not User class.

Saving Time

It still up to project manager, but definitely in large-scale projects, it saves significant time.

Standard Coding

Now other people understand your codes better than ever.

Dependency Injection Container

When you use Dependency Injection, there must be a place to injection dependencies which called container.

Using simple container makes your application messy. There will be many objects on-the-fly and global. But you can use DI packages to manage the dependencies.

Next post I will talk about Dependency Injection Container.

Published by

Milad Rahimi

I’m a software engineer with some big targets, I love what I do and nothing else matters…

Leave a Reply

Your email address will not be published. Required fields are marked *