Drupal 8 Development Mastery (5): Modern PHP Programming: Dependency Injection

I continue my exploration of the fundamentals of Drupal 8 development. Here I will explain what "Dependency Injection"  design pattern is, it's advantages and disadvantages, some code examples to show DI in action and it's relevance to Drupal 8 development mastery.

Drupal 8 Development Mastery - Modern PHP Programming: Dependency Injection

I had a hard time making sense of this one, not because it is a difficult subject to understand. Just the opposite: because its so simple, though it's name deceptively suggests a complex topic to master. My difficulty is in understanding why so simple a concept would be considered important enough to be worth an attention in Drupal 8 development literature. Upon further research however I discovered it is indeed important, not just for Drupal development, but for the wider software development practices of any significant complexity.

It is one of those simple but advanced concepts you wouldn't encounter in basic programming tutorials, because they don't make sense in simple cases. They are more of programming best practices rather than necessities.

So let me introduce Dependency Injection in as simple terms as I understands it. Dependency Injection is simply a design pattern (remember those from earlier posts in this series?) and a programming best practice that is relevant to the object oriented programming domain. It is a method of handling complexity in an object oriented situation in order to make the code more maintainable. Simply put it is a way of writing better codes to ensure better maintenance.

Dependency Injection is simply a design pattern and a programming best practice that is relevant to the object oriented programming domain.
It is a method of handling complexity in the object oriented world in order to make codes more maintainable.
Simply put it is a way of writing better codes to ensure better maintenance.

It is most useful when creating large scale projects that needs to be actively developed and maintained by a large number of developers and over a long period of time (like Drupal and other large-scale open source projects). Despite its usefulness, Dependency Injection is discouraged in simple projects or those that does not fit the above profile, like those intended only as a disposable demo.

What are the advantages of using this method of writing code?

  • It promotes writing good quality codes thereby ensuring easy maintainability of projects.
  • It makes it easy to test software codes.
  • It promotes 'loose coupling', that is, making different pieces of codes less dependent on each other. A very important principle in modern software development.

What are its disadvantages?

  • It is not suitable for simple projects or projects that will not be maintained in the long term, like demo projects.
  • It needs more time and effort to do correctly.

How is Dependency Injection realized in code? How does it actually work?

To begin to understand how Dependency Injection works you have to know object oriented programming. So from here on I will be relying on simple oop codes to explain Dependency Injection.

To start off let's attempt to derive its meaning from its name. So what is a dependency? Dependency in OOP means a hierarchy of classes that depends on each other in order to function correctly. In other words an object A depends on object B if object A requires object B in order to execute correctly. For instance, an Article class may require a database access object in order to get its contents from the database. Here we say that the Article class is dependent on the database access object.

In normal OOP style realizing this dependency is as simple as creating the required object inside of the dependent class at the point it is needed. Problem solved.

A simple example is in order here. Here is a piece of simple oop code where dependency is not injected. We will introduce dependency injection to it right after.

 

<?php
 
class StockItem {
 
  private $quantity;
  private $status;
 
  public function __construct($quantity, $status){
   $this->quantity = $quantity;
   $this->status   = $status;
  }
 
  public function getQuantity(){
   return $this->quantity;
  }
 
  public function getStatus(){
   return $this->status;
  }
 
}

class Product {
  private $stockItem;
  private $sku;
 
  public function __construct($sku, $stockQuantity, $stockStatus){
    $this->stockItem  = new StockItem($stockQuantity, $stockStatus);
    $this->sku        = $sku;
  }
 
  public function getStockItem(){
    return $this->stockItem;
  }
 
  public function getSku(){
    return $this->sku;
  }
}
?>

 

The important parts are highlighted. The Product class is depending on the StockItem class here. This dependency is being realized by creating the StockItem class right inside of the Product class codes. This is perfectly legal.

As stated earlier writing code this way may be perfectly correct in simple cases. However, in large scale, long term projects like Drupal, writing codes like this introduces a lot of difficult challenges. These challenges becomes more apparent and compounded in a situation when you started to have chained dependencies: object A depends on object B and object B depends on object C and so on. These challenges are grave enough to threaten the long term viability of such projects.

So this is where Dependency Injection comes to the rescue. So having described what dependency mean and the problems it causes in code development, let's now explore how 'injecting' it helps solve these problems and create a better code. Injection here simply means that the required object is created outside of the class that requires (depends on) it and inserted (injected) at the point it is required. Thus avoiding creating it inside of the class that uses it. This ensures that the two objects are as independent as possible thus help avoiding a whole lot of undesirable challenges.

So lets rewrite the above codes using Dependency Injection.

 

<?php
 
class StockItem {
 
  private $quantity;
  private $status;
 
  public function __construct($quantity, $status){
   $this->quantity = $quantity;
   $this->status   = $status;
  }
 
  public function getQuantity(){
   return $this->quantity;
  }
 
  public function getStatus(){
   return $this->status;
  }
 
}
 
class Product {
  private $stockItem;
  private $sku;
 
  public function __construct($sku, StockItem $stockItem){
    $this->stockItem  = $stockItem;
    $this->sku        = $sku;
  }
 
  public function getStockItem(){
    return $this->stockItem;
  }
 
  public function getSku(){
    return $this->sku;
  }
}
?>

 

The differences are highlighted. The dependency here is realized through Dependency Injection. The StockItem object is created elsewhere and introduced into the Product object already formed. This gives the later code all of the DI benefits outlined above.

Although the above example is highly simplified, and there are many other ways of realizing DI in codes, the goal remains the same in more complex cases: to minimize dependencies and create a more maintainable code.

So that’s all Dependency Injection is all about, but that is not the end of the story. In order to make DI easy to implement in a standardized way the concept of Dependency Injection Container was introduced. A lot of DI frameworks (eg PHP-DI) were also created around this concept in order to help manage DI in a more orderly manner. But these are beyond the scope of this introductory series. So explore some other sources if you want to know more. It's enough here to just understand what it is basically.

So, How Is Dependency Injection Relevant To Drupal 8?

Because this is a series on Drupal 8 development, the above ranting begs the question: How does all of this related to Drupal 8 and mastering Drupal 8 development for that matter? First of all, going from the above, Drupal 8 fits the profile of a large-scaled, actively maintained project, involving a large number of developers. For that Dependency Injection is invaluable in ensuring the long-term viability of this noble project.

Based on the above explanation you might argue that your intention of wanting to master Drupal 8 development is not to join the maintainer crew of Drupal 8 (known as core committers). True, most aspiring and established Drupal 8 developers are only interested in creating simple custom and contrib-level Drupal codes, and as such the need to learn Dependency Injection may not seem obvious.

However the knowledge of DI may come in handy when you need to study parts of Drupal 8 core codes in order to figure out what is going on under the hood or you intend to reuse some core codes in your own custom/contrib module. It may also prove invaluable when later on you wish to become a core committer. Who knows. Besides it not hard to understand, at least the basics.

Some Helpful References

Here are some useful references to help you explore the subject of Dependency Injection programming pattern more deeply:

Dependency injection and dependency injection containers are different things:
dependency injection is a method for writing better code
a container is a tool to help injecting dependencies

Next: Modern PHP Programming: Namespaces and PSR-0

Categories: 

Add new comment