Requests for comment/Dependency injection/2014

This RFC proposes a lightweight mechanism for dependency injection. An implementation with tests and examples is provided. A facility like this could be combined with improved autoloading, and we could add it to core as a first step in an iterative development process. Other options are also discussed.

Problem statement
Dependency injection (DI) is a design pattern that can facilitate unit testing, loose coupling and architecture description. Although it's more useful in some languages than in others, it is a well-established pattern, and there is a solid ecosystem of DI libraries for PHP.

Mediawiki doesn't have a dedicated DI mechanism, though adding one has been discussed, and some code in core does DI by hand. Also, Wikibase has classes for DI.

Adding simple DI support to core would be a first step towards consistent, concise use of this pattern. Since we'll probably need at least a few iterations and use cases to get it right, this first step could be a kind of "internal API beta feature".

Previous discussions
Using DI in Mediawiki has been considered before. Here are some earlier conversations about it:
 * Discussion of changes to Architecture guidelines at Wikimania 2013
 * Section on DI for external resources in Talk:Architecture guidelines
 * Discussion of TitleValue at the Arcitecture Summit 2014
 * The TitleValue RFC and the ServiceRegistry section on that RFC's Talk page

Current functionality
Here is how you can use DI with the proposed implementation.

Let's say you have the following interfaces and classes:

Assuming you want only one instance of these classes per request, you can set up and use DI like this:

(Note: the global variable  and the class   are actually called   and   in the version of the implementation that is part of the Campaigns extension.)

creates and caches a single instance of any realization class ( or , in this example) the first time it is requested via its associated interface. So when we request, an instance of   is created and cached. The next time a realization of the same interface is requested, the same object will be returned.

To instantiate,   detects the type hint in the constructor and injects the   instance.