Dependency injection

Hello,

I wanted to come back to a mechanism that you will often encounter when you develop in oop, the dependency injection.

This technique not only ensures better readability but also better maintenance.

There are several types of dependency injections, we will detail the main ones:

  • Injection by contructor
  • Injection by mutator
  • Injection by interface
  • ...

Imagine, we want to associate a Post class with the Author class:

Without any dependency injection


class Post {
    public function __construct($fullname, $website, $email) {
        $this->setFullname($fullname);
        $this->setWebsite($website);
        $this->setEmail($email);
    }

    public function setFullname($fullname) {
        $this->fullname = $fullname;
    }

    public function setWebsite($website) {
        $this->website = $website;
    }

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

We find that the two classes are intimately linked. For each field addition in the Author class, we need to adjust the Post constructor!

Let's see how to do with dependency injection:

Injection by contructor

use Author;

class Post {
    public function __construct(Author $author) {
        $this->setAuthor($author);
    }

    public function setAuthor(Author $author) {
        $this->author = $author;
    }

    public function getAuthor() {
        return $this->author;
    }
}

You must instantiate an instance of the Author class before instantiating the Post class.

Injection by mutator

use Author;

class Post {
    public function __construct() {

    }

    public function setAuthor(Author $author) {
        $this->author = $author;
    }

    public function getAuthor() {
        return $this->author;
    }
}

Here, we must use the mutator to associate classes.

Injection by interface

interface AuthorInterface {
    public function getFullname();
    public function getWebsite();
    public function getEmail();
    // ...
}
class Author implements AuthorInterface {
    public function getFullname() {
        return $this->fullname;
    }
    public function getWebsite() {
        return $this->website;
    }
    public function getEmail() {
        return $this->email;
    }
    // More stuff...
}
use AuthorInterface;

class Post {
    public function __construct(AuthorInterface $author) {
        $this->setAuthor($author);
    }
}

There are other methods to make a dependency injection more convenient and robust to use, for example containers...

Symfony framework, since 3.3 release, use PSR-11 containers.

From the official docs:

In Symfony, these useful objects are called services and each service lives inside a very special object called the service container. If you have the service container, then you can fetch a service by using that service's id:

$logger = $container->get('logger');
$entityManager = $container->get('doctrine.orm.entity_manager');

The container allows you to centralize the way objects are constructed. It makes your life easier, promotes a strong architecture and is super fast!

Read more

See you soon,

Mathieu