Mr Treublaan 1-3
1097 DP Amsterdam
The Netherlands

Dependency injection in Drupal 8, an introduction.

13 Feb, 2015 Drupal

Home Blog Dependency injection in D...

Drupal Dependency injection

So, like a bunch of other Drupal people, we're also experimenting with Drupal 8; for our Drupal distro OpenLucius. Us being 'less is more'-developers, one aspect we really like is dependency injection.

First things first, for all new developers we should explain exactly what dependency injection is. Dependency injection is an advanced software design pattern. It implements “inversion of control”, this sounds complex but it basically means that reusable code calls task specific code.  (Reference: http://en.wikipedia.org/wiki/Inversion_of_control)

What does this mean for us Drupal developers? It means we can write more efficient code by reducing the load. We only load what we need. 

Types of injection

There are multiple types of Dependency injection:

  1. Constructor injection, where the dependency is injected through a class’s constructor.
  2. Setter injection, where the dependency is injected through a setter method of a class.
  3. Property injection, where a public field of a class is directly set.

All three methods have their pro’s and con’s I’ll try to explain these three in detail.

1. Constructor injection

There’s no real downside to using constructor injected dependency injections. The advantages are:

  • Constructor injection can ensure that a class cannot be constructed without a required dependency.
  • The constructor is only called once so the dependency cannot be altered afterwards

These two advantages do not limit the ability to use optional dependencies; these can be implemented using one of the other methods.  It does however tend be a bit more difficult to extend the class or override the constructor.

Simple example of constructor based injection:

class SimpleClass {  protected $variable;  public function __construct(\SimpleType $variable) {    $this->variable = $variable;  }}

As you can see the SimpleType class is injected into the protected variable of the SimpleClass. Basically that’s all you have to do to :)

2. Setter injection

This type of dependency injection is often used for optional requirements as the only thing you have to do to prevent adding a dependency is not calling the setter.

The advantages are:

  • The above-mentioned, setting of optional dependencies.
  • You can call a setter method multiple times. This also allows you to add multiple dependencies using only one method.

The downsides are:

  • The setter can also be called after the construction of the object. Therefore you can’t guarantee that a dependency is not replaced.
  • You can’t be certain that a setter is called at any moment in time. So you have to implement a method to verify if a dependency is indeed injected.

Simple example of setter-injection:

class SimpleClass {  protected $variable;  public function setType(\SimpleType $variable) {    $this->variable = $variable;  }}

3. Property injection

Injecting  directly into class objects is not advisable but there’s a small possibility that a thirdparty library implements public properties.

The downsides are:

  • There is no way of controlling whether a dependency is set. It can be changed at any point.
  • You can’t use type hinting to verify what type of dependency is injected. (type hinting is a way of ensuring that an object is of a certain type. For more information have a look at the phpdocs http://php.net/manual/en/language.oop5.typehinting.php)

Simple example of property injection:

class SimpleClass {  public $variable;}

Wanna stay informed?

Monthly Newsletter →

Dependency injection Drupal

All of this was PHP dependency injection, which can be easily implemented in Drupal 8. I’ll show two simple ways to implement these three methods, which can be downloaded as an example module at the bottom of the page. I’ll show a direct approach to using these 3 methods and a service-based approach. Both are quite simple to implement.

For demonstration purposes i’ve created simple module containing the four classes now properly named in a namespace called ‘Drupal\dep_test’ where dep_test is the name of the module.  The classes are now distinguishable from each other:

  • SimpleClassConstructor
  • SimpleClassSetter
  • SimpleClassProperty
  • SimpleType

Within this module I’ve added a simple Controller, which makes it easy to display values. In the controller class I’ve added the following code for a direct approach:

// Initiate the Classes.$this->constructor = new SimpleClassConstructor(new SimpleType());$this->setter      = new SimpleClassSetter();$this->property    = new SimpleClassProperty();// Inject dependencies.$this->setter->setType(new SimpleType());$this->property->variable = new SimpleType();

As you can see a direct approach is quite simple to implement. Now we’re going to use a service based approach. For this we’re going to use a services.yml file.

This file contains the services and the function calls / properties to be set.

services:  deptest.simple_type:    class: Drupal\dep_test\SimpleType  deptest.constructor:    class: Drupal\dep_test\SimpleClassConstructor    arguments: ['@deptest.simple_type']  deptest.setter:    class: Drupal\dep_test\SimpleClassSetter    calls:      - [setType, ["@deptest.simple_type"]]  deptest.property:    class: Drupal\dep_test\SimpleClassProperty    properties:      variables: "@deptest.simple_type"

From top to bottom:

  • We define the simple_type service and tell, which class should be used.
  • We define the constructor service, set the class and give the simple_type class as an argument.
  • We define the setter service, set the class, set the function call and the argument for the function call.
  • We define the property service, set the class and set the property to the simple_type class.

Now if we call one of these services using the service container all properties will be set, just like the direct approach.

  $this->service1 = \Drupal::service('deptest.constructor');  $this->service2 = \Drupal::service('deptest.setter');  $this->service3 = \Drupal::service('deptest.property');

Calling the service container directly is not advisable but for demonstration purposes it should suffice.

The end

That’s about it for this blog item. I hope it helps someone. Don’t forget to download the full package and have a look at the code.

Download example code

Download it here

 

Written by Joris Snoek | Feb 13, 2015
Let's Talk

Please tell me all about your project!
Mail , or send a message:

Got some more time?

Related content
09 May, 2023 Drupal

Save time, frustration, and potential content loss.


07 Jun, 2021 Drupal

Programmatically in multiple Views


02 Jun, 2021 Drupal