So where should our dependencies be created in a full object application? In a special object which is only responsible for dependency instantiations?
You have 2 options:
- you create all the objects yourself, at the root of your application, i.e. in your front controller (index.php) for example. If you application is a bit big, that becomes quickly a hell.
- you use a Dependency Injection Container. That object will be responsible of creating objects (and injecting them their dependencies in the constructor). Same here: you have to use/call the container only at the root of your application, i.e. in the front controller (index.php) for example.
If yes, what is the name of this object and how to define it? Is it what we call "controller"?
That's the Container. To give you an example, here is PHP-DI - Understanding DI.
You can use dependency injection on the controller (and I would recommend to do it): you can get dependencies in the controller's constructor (just like in any service). Some frameworks makes that difficult though (Symfony for example).
This "controller", what is the right way to unit test it? Should we unit test it?
No really. Some containers allow you to configure "Factories" to generate some objects.
For example, if creating the DBConnection object is complex, you could write a factory class, that has a method that creates the DBConnection object. So you could test the factory class. But I wouldn't say that's necessary.
In a full POO application, how to avoid passing our objects (often the same) between classes?
You should never pass instances around, because you should never call a constructor: all objects are constructed by the container.
So it becomes really simple: you write each class by taking dependencies in the constructor, and that's it. You don't care about dependencies and what those dependencies need.
For example, a DB object, Log, ... In this way, we take the risk to have constructors with many parameters, don't we?
Yes. You said you expect to have like 15-20 parameters in the constructor: that's not good at all.
You should generally try to have 2-3 parameters maximum. Having to many means that your class has too much responsibilities, it does to many things.
You can try splitting up the code of your class into several smaller/more targeted classes, or use events for example.
If we take your example, your printer could rather be like:
public function print($file) {
$this->driver->print($file);
$this->log->log('File has been printed');
$this->monitor->sendCount(1);
$this->statsUpdater->increment();
}
It makes more sense: a printer prints a file.
It's one dependency less (the queue). And then you can have a PrintQueueProcessor
that watches the queues, takes the next file and calls the printer to print it.
The printer does one job (print a file), the queue processor does one job (unqueue files to print them).