This RFC proposes the following to be adopted as best practice:
1. When a service (or application logic) needs access to another a service, it asks for it in the constructor. This is the actual injection of dependencies.
* Access to global default instances ("singletons") should be restricted to static entry points (e.g. hook handlers and callbacks in bootstrap code).
* Services are constructed by other services (factories and registries being special types of service). At the top of this chain of registries/factories there is the top level registry aka application scope.
* Objects that need access to services can only be constructed via factories (not directly using the new operator).
* Services should be represented by narrow interfaces (e.g. UserLookup).
* Injecting/passing around factories, registries, and especially "kitchen sinks" like RequestContent should be avoided.
* Registries use constructor callbacks (aka factory functions) to instantiate services.
* Bootstrap code should avoid instantiating services.
* Mutable global state should especially be avoided.
These principles effectively provide dependency injection "on foot", without the need for a DI framework or a declarative syntax for networks of service objects. Decisions regarding the life cycle of service objects (lazy initialization, etc) are left to plain old PHP code.
NOTE: Proposal reworked October 2015. Please see the full version of the proposal, including example code, at <https://www.mediawiki.org/wiki/Requests_for_comment/Dependency_injection>