1

Why is this

__construct(MyService $my_service ) {
   $this->my_service = $my_service;
}

create (ContainerInterface $container) {
  return new static(
      $container->get('my.service'));
}

better than

__construct() {
    $this->my_service = new MyService();
}

?

3
  • Read up on SOLID principles.
    – Kevin
    Mar 2 '18 at 4:04
  • Not sure how this doesn't relate directly to Drupal. Perhaps the title is incorrect. I'm not asking about dependency injection per se, but rather about the Drupal 8 convention of using the ContainerInterface and a "create" function, rather than just instantiating the dependency in the constructor. Mar 5 '18 at 19:33
  • I believe because this way you can specify in the constructor what you want, like an Interface, which makes it swappable for other implementations as long as they adhere to that contract without having to change the constructor code. If you just do new Object() within constructor, its less flexible and more coupled. code.tutsplus.com/tutorials/…
    – Kevin
    Mar 5 '18 at 19:40
1

From Services and dependency injection in Drupal 8:

... is best practice to access any of the services provided by Drupal via the service container to ensure the decoupled nature of these systems is respected.

A clear example can be found in Drupal 8 Dependency Injection, Service Container And All That Jazz:

Take the following simple class:

class Car {

  protected $engine;

  public function __construct() {
    $this->engine = new Engine();
  }

  /* ... */

}

When you instantiate a new class Car you go like this:

$car = new Car();

And now you have an object handler ($car) that has an $engine property containing the handler of another object. But what if this car class needs to work with another engine? You'd have to extend the class and overwrite its constructor for each new car with a different engine. Does that make sense? No.

Now consider the following:

class Car {

  protected $engine;

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

  /* ... */

}

To instantiate an object of this class, you go like this:

$engine = new Engine();
$car = new Car($engine);

Much better. So now if you need to create another car using another engine, you can do so easily without caring about the Car class too much since it is supposedly equipped to work with all the engines in your application.

$turbo = new TurboEngine();
$car2 = new Car($turbo);

And that is dependency injection. The Car class depends on an engine to run (dooh), so we inject one into its constructor which then does what it needs to do. Rather than hardcoding the engine into the Car class which would not make the engine swappable. Such constructor injections are the most common but you'll also find other types such as the setter injection by which we would pass in the engine through a setter method.

So there you go. Dependency injection is a very simple concept that has to do with the practice of decoupling functionality between classes. By passing dependencies to objects we can isolate their purpose and easily swap them with others. Additionally, it make is much easier to unit test the classes individually by passing mock objects.

Not the answer you're looking for? Browse other questions tagged or ask your own question.