Dependency Injection (PHP-DI)

Automated testing is great, but whether it’s easy to write or not depends on your code design. As a rule of thumb, the more loosely coupled your classes are, the easier they are to test. And one can’t talk about loosely coupled classes and not mention dependency injectionarrow-up-right.

One simple example should clarify how it works. Imagine a class that encountered an error and wants to log it. Let’s also assume you’re using Monolog arrow-up-rightto create loggers that handle these events. Without dependency injection, whenever the class encounters an error it must now instantiate a logger and use it. If you have 50 classes that use loggers, you would write the code for instantiating a logger 50 times in 50 places (well, you’d probably write a function somewhere to simply retrieve an instantiated logger and that too would be a sort of dependency injection, in a nutshell).

With dependency injection, you would create a logger at some point in time and then simply pass it along to each class that can log errors (traditionally, in the constructor or through a method like set_logger). That way your classes don’t actually know what a logger is or how it works or how to get one — they simply get one passed along.

Normally you wouldn’t even bind yourself to any specific logger but you would use an interface. Luckily, for loggers, there already exists the PSR-3arrow-up-right standard (which Monolog also implements). So your classes simply expect a PSR-3 LoggerInterface object passed on in the constructor.

When you write automatic tests for your classes, you don’t need to actually load Monolog too! You can just pass on any PSR-3 implementing class, or just use Mockery arrow-up-rightto create one on the fly.

Dependency injection containers usually provide an array of features that are much more powerful than just that (e.g., auto-wiring or on-the-fly instantiation). For our projects, we use PHP-DIarrow-up-right but this is not actually a requirement for using our framework. The framework accepts any PSR-11arrow-up-right-compatible container and only assumes the features that PSR-11 foresees.

Last updated