What is the difference between a dependency injection container and using composition root? I’ve been looking at examples online and they seem vey similar and can’t find a clear answer.
Don’t they both store information about what classes depend on what and take on sole responsibility for creating objects? And then if dependencies change you just have to change it in one place.
An additional question: do either reduce the number of parameters you pass to your objects — or do they simply do poor man’s DI behind the scenes? The reason I ask is I have taken on a project that has a bootstrap script that creates a library object that is a container for all other objects each model for the application requires (it is custom MVC) and then injects the library object instead of each object separately, presumably to reduce the number of parameters in the constructor. What is this called and is it good/bad practice?
A DI container and a composite root are two different concepts.
A container is just a collection of factories that takes care of wiring up your various dependencies.
Basically the composition root should be the only section of your code to directly use the container. In other words, the root is the only spot where you should see things like $container->get(‘service_id’);
It sounds like the container is being injected to some of your library objects. And they in turn pull additional dependencies (service locator pattern) from it? In general it is recommended that you avoid passing the container in to other objects. By passing the container you are basically giving your objects global access to all services. Makes it harder to understand what your class is doing.
On the other hand, there are cases where passing the container makes sense. Especially when you can’t determine in advance exactly which services an object might need.
Thanks, that’s good to know they’re not either or!
The code I am looking at is not passing a container as such. This is a simplified example form the Bootstrap class:
$lib = new Lib();
$lib->objs['db'] = new DB();
$lib->objs['logger'] = new Logger();
$lib->objs['emailer'] = new Emailer();
// ...and so on
$model = new Model($lib);
// Presumably so you don't need to do $model = new Model($db, $logger, $emailer /* and so on */);
It seems the bootstrap basically prepares all library objects needed for that request and stores them in a single object and injects that into all objects used for all the models/application.
I guess the Bootstrap class is technically the composition root then. The library object uses composition, right? Which I know is regarded as good practice but this approach seems to create a single collection of library objects and passes them around. So, it reduces the number of parameters.
Is there a name for this and is it really bad practice? I suppose at least the classes themselves aren’t creating all the objects themselves.
Basically you are building a Registry object ($lib), injecting it into your Model and using the service locator pattern to extract dependencies as needed.
Typically the Registry is actually a global and any time an object happens to need say a logger it simple reaches into the global registry and pulls it out. So the fact that your code is injecting the registry is a good thing as it helps to restrict access to global services.
Of course I suspect that if you Model object happens to need to create more objects then it passes the registry on to them. So the registry ends up being more or less a global anyways.
I don’t think it is accurate to say that the library is using composition. The Model object is using composition because instead of trying to inherit from some base db/logger/emailer root class, the model object is composed of db/logger/emailer classes along with whatever model specific functionality it does.
Is it bad practice? A lot depends on how your model object uses the registry. Something like:
class Model {
private $logger;
private $db;
private $emailer;
public function __construct($lib) {
$this->logger = $lib->objs['logger'];
$this->db = $lib->objs['db'];
$this->emailer = $lib->objs['emailer'];
Is not too bad. The constructor locates the services it needs and then discards the $lib object. You can tell by looking at the constructor just which dependencies are needed.
On the other hand, if $lib is stored in your object and accessed whenever a service is needed and passed around to other child objects then, yes, I would classify it as a bad thing.
Ultimately of course it up to you to decide. Does your current application work and can it be updated without much fuss? If so then consider yourself lucky and go with the flow. Otherwise, it might be time to look at using a modern container.
Almost forgot. If this pattern was adopted in order to reduce the number of constructor arguments then the real problem is that your Model classes probably have too many dependencies and are trying to do too much. There are always special cases but anytime a class has more than three or four dependencies then it is worth taking a look at.
The purpose of dependency injection is to achieve loose coupling between different components. Passing an object with all dependencies in the system to every class is a direct violation of that methodology. Older frameworks follow a similar pattern to what you have but newer, modern frameworks use dependency injection containers that manage instantiation and injection of only necessary objects. From a purist perspective passing the container to every class is wrong. If you want a nice lightweight container php league has one that I would highly recommend.