In the previous two posts (available here and here), I talked a bit about the Singleton Design Pattern, dependency injection, and dependency injection containers.

Singleton Design Pattern as a Dependency Injection Container

Not that kind of container (but it’s still a cool shot).

These are all topics that I think are important for developers to know and to understand. If you’ve not read the previous posts, then I recommend it because the code that’s shown later in this post assumes you know a little bit about each of the topics mentioned above.

Furthermore, this is going to be a bit shorter as it relates to the previous two posts. The purpose is simply to show how to use a singleton as a simple dependency injection container.

The Singleton Design Pattern as a Container

Before showing the code for how to use the Singleton Design Pattern as a dependency injection container, I want to make two things very clear:

  1. Using a singleton as a dependency injection container does not replace a true dependency injection container.
  2. True dependency injection containers offer more functionality than what we’re going to see here.

The primary purpose of showing this as a potential strategy is because there are times in which we want to implement best practices.

But we don’t always have a chance to do so because of some external circumstance (the least of which isn’t some of the pressures that come with deadlines, etc.).

Ultimately it’s a matter of pragmatism for, say, the first version of the project. It’s something you can always go back and refactor.

With that said, here’s a look at one way that a singleton can be set up as a dependency injection container.

Since this is based on code that I’ve previously shared, there should be very little that’s new. The primary thing to notice is the introduction of an associative array that we refer to as a registry.

This is the place where objects are stored (and identified by a key). Ultimately, this allows us to grab an instance of the Container and then get an instance of the object (by it’s key) we need when we need it.

A Missing Feature

If you recall from the previous post, a container is supposed to handle a few details that this one does not handle:

It deals with the instantiation and setup of our dependencies for us and allows us to just specify them in a configuration file.

In this case, we have the manually instantiate the object then add it to the Container using the available method. Though, it wouldn’t be too hard to introduce this functionality.

Even still, this is okay – in the short term. It shouldn’t stay this way. But that’s not the purpose of this series of posts.

Pragmatism Over Purity

I know that more experienced developers who have read through this series of posts (or even just one of the posts) are likely to disagree with many of the things I’ve said.

And that’s okay.

I’ve tried to reiterate the purpose of this is to leverage pragmatism over purity. The latter can almost always come later, but the former is something that we can implement as we go along when time is short or constraints are tight.

Regardless, the larger picture of high cohesion and less coupling is another thing we should strive for, and if this helps get us one step closer towards that general goal, then I think it’s a good thing to practice.


Join the conversation! 4 Comments

  1. In my opinion, there’s absolutely no need to make the registry property static.

    Also, why make the constructor private? A public constructor doesn’t affect the static single-instance usage of the container at all. Having global/static access to a unique indtance is good enough here, I’d say. No need for a real (inconstructible) singleton class, IMO.

    Lastly, I’m not sure that throwing an exception in Container::add() is necessary. Just return (false).

    • Making the registry property static is one of those carry overs for me where, since each value is shared across the single instance of the object then it would be static. 

      Either way, I can adjust the code just as well.

      The constructor is provide so that the only way to gain an instance to the object is via the get_instance method. That way, no external classes can instantiate it. Only the get_instance method provides the means for doing that.

      And your point about the Exception is right — this is more or less based on some previous work I’ve done where I was try/catching something around the Container. Returning false is fine, passing the buck and having the client class handling it either via catching it or via checking for false is just as well either way, IMHO.

      • Regarding the private constructor: my actual question should have been what you gain by making the class not regularly constructible. If you really want to make it accessible through the getter only, you’d have to take care of __clone() and __wakeup() as well. And then there still is reflection…

        • Ah, that makes sense. 

          Frankly speaking, my experience with using PHP’s __clone() and __wakeup() functions are nil. I come from a bit of a different background (though I am familiar with reflection :).

          Nonetheless, all of this has provided with more than enough food for thought and practical application for how to reorganize this, or implement something some strategic my next time around.

Leave a Reply