I’ve just read some threads about DI and someone complained about complexity involved with DI. I just wanted to clarify that the concept of DI is simple, the implementations of DI frameworks tend to be complex.
Following is a example how DI could work without any framework level code. With anonymous functions, it’s actually extremely flexible and simple.
Please note that the code is just written down to make some sense but it’s not perfect, nor error free.
$deps = new stdClass;
$deps->db = new DB('user', 'pass', 'etc');
$deps->auth = new Auth();
$deps->user = new User($db, $auth);
$deps->session = new Session('ttl');
$deps->session->setUser($user);
$deps->router = new Router();
$deps->behaviorFactory = function($behaviorClass, $model) {
return new $behaviorClass($model);
}
$deps->modelFactory = function($modelClass) use(&$deps) {
return new $modelClass($deps->db, $deps->behaviorFactory);
}
$deps->controllerFactory = function($controllerClass) use(&$deps) {
return new $controllerClass($deps->session, $deps->modelFactory);
}
$deps->dispatcher = new Dispatcher($deps->controllerFactory, $deps->router);
// start the dispatcher somewhere
If someone is able to figure out some major flaws (in terms of functionality) in that approach, i’m happy to hear, i can’t imagine any right now.
Nevermind, after a second look I can see what you’re trying to do.
Looks quite clever!
How can you handle situations where certain classes require a new instance of an object? For example if your model class wanted a different version of behaviorFactory.
You both refer to same problem from different perspectives. Note that the factories do accept class names, so you can retrieve different objects with them. This could also be extended with some flow control, asking which class is requested and injecting additional dependencies. It’s just a way to resolve dependencies at “runtime”.
Not a major flaw, but I do see a small negative effect on using this code: you now always instantiate each and every possible dependency before starting to wire the objects together. It’s a minor issue, but it’s not that every request specifically uses the database, session or user, so this might become a bottleneck? Putting them in a (anonymous) function which returns a new instance when it’s called would probably fix the issue.
You could place the instantiation in a block. I kind of think it would be simpler if you always did this. You would then basically have implemented “needle” (an old Ruby DI tool) in PHP. Fabien Potencier does something similar in his PHP talks.