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.
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