Creating a Dependency Injection (DI) Container

Creating a Dependency Injection (DI) Container

A while ago, I've created a small PHP framework. In order to adhere to modern practice (it even has basic middleware support even if I don't like them), I had to pick a DI container. The issue was: either there were too complicated, or too simple. And also, sometimes I like to reinvent the wheel.

But what is a DI container exactly?

To make it simple, a DI container is a class used to instantiate other classes based on definitions. An interface has been defined in the PSR-11 about Container interface.

Why create my own

To be honest, it wasn't really the plan. I found out devanych/di-container and I was really impressed by the simplicity of it. But there were a few things I wanted to improve.

First, I wanted the DI container to fit in one single class. In order to do that, I had to convert the Exceptions to anonymous classes extending the base PSR interface.

And then, there were a couple of other features I wanted to have:

  • Picking dependency by name if they returned the proper type
  • Allow overriding distinct parameters
  • Call methods after instantiation (not everything can be set in the constructor)

Actually, I managed to fit all that under 300 LOC so I'm quite happy with the result. Of course, it's not as featured as PHP-DI or the Symfony DI component, but if 300 LOC do the job, why use more?

What is a minimalist container?

I had a discussion today on Reddit about Capsule 3 that was recently released. The package shared a lot of my own goals:

  • No cache (because it shouldn't be necessary)
  • PHP configuration (no yml, special syntax, etc)
  • Predictable output (always return the same instance once loaded)

But there was one key difference: it uses a Definition object instead of a plain array. While this may seem like an improvement, it's not perfect in my opinion:

  • It makes the package more complicated than needed (and you need to test it)
  • At the end of the day, you end up passing "magic" key/values to the argument method anyway, so it's not like the definition object help you to pick the right value (at least, a real config object would allow typed settings).

So... arrays it is for me.

Conclusion

Well, I'm not sure where I'm going with this article :-) hopefully you picked some interesting stuff or it helped you think differently about the topic.

If you want to learn more about my approach, you can also read the docs