Yes, we use static classes. So that must mean the principle advantages of dependency injection are impossible right? Wrong.
Dependency injection is about making it possible to completely replace a part of the composition of objects that work together. To reach this goal you should never use "new Object" but always expect the new object to be given or set on your class. The reason you don't use "new" is that you don't want to be tied to that specific class, you want to be able to "inject" another implementation without trouble. It is however still possible to use the object because you know what interface it extends and you know what to input and what to expect as output.
In Fuel we don't use or implement Dependency Injection in the sense that we use setters or in the sense that we give a specific object to the constructor. Thus this blog is meant for those open to alternative solutions, those interested only in the specific aforementioned implementation are probably best served elsewhere.
We have implemented the framework in a way that allows for complete replacement or extension of a class without rewriting a single line outside of that class. This has been done in 2 ways:
In Fuel any class from the core can be extended or replaced in the global namespace. This new class will then be used by the core classes as well as by your application. The way this has been done is that all core classes live in the "Fuel\\Core" namespace and when a class like "View" is requested and not loaded into the global namespace we check the Core for the class, load it and alias it to global. If you want to use another implementation you can just extend or replace the core class in the application (or a package) and register it with the autoloader. After that your implementation will be used everywhere instead of the original Core class.
This isn't really injecting of course in the classic way, it uses an expected classname to access an unspecified class. Thus the injection is in a way to the expected classname.
The question is if this is really that different from expecting a specific interface. It may not look like classical dependency injection, that doesn't mean it can't reap the same benifits.
Another way we have used to implement the principle of dependency injection is by using drivers for some classes. The Session class for example is always accessed through either static usage or creates a new object with a factory:
// use your default driver to retrieve a value "some_var" from the session
$some_var = Session::get('some_var');
// use a specific named config to retrieve a value from that session, you can change
// the config if you want
$session = Session::factory('admin');
$some_var = $session->get('some_var');
To some this may look like a fixed class, but in truth you're workin with Session_Cookie, Session_Db, Session_Redis or any other driver you might configure it to use. Again in this case: nothing is set on my object or given as a construction arguement but I can replace/configure it to use any replacement or extension I want without changing the existing code that uses the implementation.
While we haven't implemented Dependency Injection in the classical sense, we do allow you to "inject" anything you want. The limitations for both the classic and our solution is that the interface must stay the same, but instead of expecting a variable on your object you can use static class calls. I know that we'll never agree if you're a purist/evangelist, but if you're a pragmatic coder our options with drivers & extensions will probably serve your needs just as well.