Explain Dependency Injection Container like I'm five

I'm having a hard time wrapping my head around a DI package for PHP (PHP-DI). And why exactly would I want to use it?

Also, how it is different from simply instantiating a class wherever you want?

You can explain the title in regards or regardless to any particular language.

Did you find this post useful? Show some love!
Ben Halpern DEV.TO FOUNDER

Hey there, we see you aren't signed in.

Please consider creating an account on dev.to. It literally takes a few seconds and we'd appreciate the support so much. ❤️

Disclaimer - I'm not hugely familiar with PHP, basing this off my experience of other languages!

Say I'm writing an app and I need MyClass to use an instance of MyDependency. The easiest approach, as you suggested, would just be to do new MyDependency() and be done with it. In a lot of scenarios, that's totally sufficient!

// No dependency injection

class MyClass {
    private $myDependency;

    public function __construct() {
        $this->myDependency = new MyDependency();
    }
}

But the tricky part comes if you want to make MyClass be able to use lots of different versions of MyDependency - what if MyDependency calls out to the network and you want to replace it with a mock? You could add a load of branching logic to decide which version to use, but that gets messy quickly.

A better option is to use the old principle of 'dependency inversion' - rather than constructing the dependency in MyClass, you take it in through the constructor or a setter, letting the parent of MyClass decide which version to use. Again, in a lot of cases this will suffice!

// Manual dependency injection

class MyClass {
    private $myDependency;

    public function __construct(MyDependency $myDependency) {
        $this->myDependency = $myDependency;
    }
}

So where does a DI container like PHP-DI come into things? Well, if you're constantly having to manually inject your dependencies, it can be quite tedious/inflexible - you only ever mock MyDependency in tests, yet suddenly you're having to explicitly pass an instance in every time you want to use MyClass!

A DI container provides an extra layer of wiring on top of this to make things easier and more configurable. For example, PHP-DI offers 'autowiring' functionality that will automatically inject dependencies into your classes' constructors, and a configuration API that lets you set which versions get used. Now rather than having to manually inject your mocks everywhere you use MyClass, you can just change the container config! This does, however, come at a bit of a cost - now if you want to create an instance of MyClass, you have to do it through the container's API rather than simply calling new.

My advice would be, unless you know from the start you're doing to need the flexibility/configuration that a DI container provides for your project, start with one of the simpler ways of doing it - you can always add it later if you find yourself needing it!

I'm sorry for my inadequacy. But, what do you mean when you say lots of different versions of MyDependency? Are you referring to polymorphism?

Yep, polymorphism is what I was referring to, apologies if that wasn't clear! In the second example, MyDependency could be an class with multiple sub-classes or an interface with multiple implementors.

Thanks so much for making it clear.

Classic DEV Post from Feb 12

I just got a Raspberry Pi 3. What can I do with it?

Just got a Raspberry Pi 3 setup and it's my first one. If you own a Raspberry P...

READ POST
Follow @michael to see more of their posts in your feed.