Dependency Injection is one of those programmer-y terms that sounds far more complicated than it is.

As defined in Wikipedia:

Dependency injection allows a program design to follow the dependency inversion principle. The client delegates to external code (the injector) the responsibility of providing its dependencies.

The client is not allowed to call the injector code. It is the injecting code that constructs the services and calls the client to inject them. This means the client code does not need to know about the injecting code.

But think about it like this (because if you’ve used object-oriented programming, you’ve no doubt done something like this):

  • You have a class, say Class A that maintains a reference to another class, Class B.
  • In the constructor for Class A, we instantiate Class B and set it equal to a property.

Easy enough, right? Here’s the implication:

Class A now has a dependency on Class B and that dependency is only set during the instantiation process in the constructor of Class A.

On a small scale, this isn’t that big of a deal but as a plugin or an application gets more and more complicated, there are all of these dependencies set in the system without any way to necessarily test them in isolation.

And don’t get me wrong: There should be some cohesion among objects in an application, but the degree to which they are coupled should be small. There are a lot of reasons for this many of which are outside the scope of this post.

To help mitigate this, programmers have created all kinds of strategies to make sure that our classes can be small and focused and tested in isolation all the while working with other parts of the system.

And one of the most popular ways to do this is through dependency injection. But what does dependency injection in WordPress look like (and is it any different than in other applications)?

Dependency Injection in WordPress

Given the fact that dependency injection is one of those topics that has permeated software development for years (decades, even?), and it would only make sense that it’s something we should look at regarding WordPress.

At least, I think this is something that’s true for those who take an object-oriented approach to building solutions with WordPress such as plugins, web applications, and other similar projects.

And when it comes to talking about dependency injection, there are two ideas are discussed together:

  1. the types of dependency injection,
  2. dependency injection containers

In case it wasn’t clear earlier in the post, I’m not a fan of the term “dependency injection.” It sounds like classical jargon used by programmer-types in that it takes a simple idea and makes it appear more complicated.

Dependency Injection

Dependency Injection as illustrated by Dwi Ardi Irawan.

Most programmers, relatively early in their education – formal or not – in their hobby, or their career quickly understand the idea of passing variables into other functions. I mean, a function accepts parameters. We pass values into these functions which become the function’s arguments and then the function runs its algorithm using these values.

Easy enough.

But when it comes to passing references to objects into other objects, it stops being referred to as an argument and becomes a type of injection.

Yes – like a medical term, but I digress.

Types of Dependency Injection

Dependency Injection is often discussed in two main ways (though there really are more than that). And the two types that people like me (and probably those of you reading this) talk about are:

  1. Constructor Injection. This is when a dependency of an object is passed into a class through its constructor.
  2. Setter Injection. This is when a dependency of an object is passed into a class through a function (usually a set function or a set_acme function).

And though it’s a simple idea, one advantage to doing this is that the initial class is no longer responsible for instantiating its dependencies. Furthermore, Class B is now passed into Class A such that we can instantiate it outside the context of Class A.

This decreases coupling, increases our ability to work on code in a more isolated manner, allows us to have a greater degree of testing, and makes it possible to work on more advanced things such as creating mock objects and other strategies that are outside the scope of this post.

Dependency Injection, What Now?

Dependency injection (or passing one object into another object :) is simple enough to understand. But the second component to this that’s useful is what’s called a dependency injection container.

This is where the idea of dependency injection gets a bit more complicated. The ideas behind it are very useful, and there are some tools, libraries, and other tools available for us to use.

But before going that far, I’d rather talk a bit about the concept of a dependency injection container and how we can write a simple one for smaller projects. Then we can talk about some of the third-party libraries that are available.

This is one area in which I really think WordPress plugin developers have the opportunity to make massive improvements in the organization of code. Myself included.

Unfortunately, so much of the material about this kind of stuff that’s available for reference via Google is still complex or uses just as much jargon as the title of the topic at hand.

Hopefully, what I’m discussing here and in future posts bucks that trend. But if not, don’t hesitate to let me know in the comments.

Category:
Articles
Tags:
,

Join the conversation! 2 Comments

  1. Hey Tom,

    Aw, man, you’re constantly writing about topics where I feel the urge to participate in the discussion, lately. Don’t you know I have work to do?

    Although I agree that a technical implementation of dependency injection itself is a pretty simple thing (passing an object as an argument), I think it tends to make people focus on the wrong thing and missing the point.

    Dependency injection is not so much about passing objects as arguments, but rather about the actual point of instantiation of these objects. The point where you instantiate an object (using new in PHP) creates a tight coupling to the class being instantiated, as you need to name the exact class being instantiated at that point. And you want to extract that point out of your inner code (code in an inner layer like the business logic layer, which is your long-term code) and get it into your outer code (your infrastructure layer, which is your short-term code because it needs to keep changing with technology shifts).

    Normally, what you’re after is Dependency Inversion, and dependency injection is one of the technical means of achieving that. The basic concept of dependency inversion is that you don’t code one concrete object against another concrete object, coupling them very tightly, but rather that both objects are coded against a common interface. These makes each of them be independent of the other, and they both be replaced without necessitating changes in the other.

    So, to get back to the example scenario you’ve posted:

    You have a class, say Class A that maintains a reference to another class, Class B.

    In the constructor for Class A, we instantiate Class B and set it equal to a property.

    Class A should not maintain a reference to Class B, it should maintain a reference to an object that implements the specific interface it needs – let’s call it Interface Z. Class B then implements Interface Z, and can be injected. Class A’s code does not know anything about Class B, it only uses methods of Interface Z.

    This opens up the possibility, later on when the requirements have changed, to have a new Class C implementing the same Interface Z, and be injected in place of Class B. Class A is completely oblivious to this change, and just continues to happily peruse its interface. So, by only coding against interfaces, you’ve just isolated necessary changes to one class, instead of potentially the whole system (Changing Class B requires changing Class A; changing Class A requires changing Class F; changing Class F requires changing Classes S and V; …)

  2. Don’t you know I have work to do?

    Wait, that’s a requirement for blogging? Oh my. :)

    Dependency injection is not so much about passing objects as arguments, but rather about the actual point of instantiation of these objects.

    You’re right, but doesn’t that seem to be implied? I mean, the object has to be instantiated in order to be passed in as an argument, right?

    Everything else you’ve mentioned in this part of your comment, I completely agree with. I’m just asking about this one point because maybe my viewing it as an implication is misguided.

    Normally, what you’re after is Dependency Inversion, and dependency injection is one of the technical means of achieving that.

    But doesn’t dependency inversion assume a knowledge of UML or a basic conceptual model of how the objects are organized and the direction in which the dependencies are “pointing?”

    If that’s the case, is it really required to understand? I would say that understanding injection is more important whereas the concept of inversion is optional. Sure, it enhances the understanding, but is it a pre-requisite?

    The basic concept of dependency inversion is that you don’t code one concrete object against another concrete object, coupling them very tightly, but rather that both objects are coded against a common interface.

    Agreed.

    Class A should not maintain a reference to Class B, it should maintain a reference to an object that implements the specific interface it needs – let’s call it Interface Z. Class B then implements Interface Z, and can be injected. Class A’s code does not know anything about Class B, it only uses methods of Interface Z.

    Absolutely, but this is a topic that takes some time to work through. To me, it’s a matter of first understanding the basics then working one’s way up through the concepts of abstraction.

    Sure, we can start at the most generalized form of it but for those who have never seen object-oriented programming or those type of concepts, it makes it more difficult to have something practical to walk away with whereas approaching it from the other way at least gives something they can apply and then begin to refactor and generalize.

    At least that’s how I approach it :).

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.