I must admit he got me interested by the provoking title and watched this video. In my opinion he is very knowledgeable and he has really grasped the concept of OOP, that’s why he might appear extreme to some people. But we need to be practical as well - I’ve done some programming in Java and in that language it is much easier to achieve OO purism, however in PHP it’s more difficult because many aspects of PHP remain procedural at the core, for example primitive types like strings are not objects, a huge collection of procedural functions, etc. Also, in Java sometimes it seemed a bit too much to have to instantiate a bunch of objects and wire them together with another object just to do a simple thing, like format a number or string, whereas in PHP I can use a single function to do the same thing. Here we go into the area of personal preferences so I don’t want to say which way is better.
His idea of not using a DIC but instantiating the application object with a large constructor is good from the OOP perspective but we need to consider he is talking about Java. When you instantiate an object with hundreds of other objects as dependencies you are actually instantiating all those hundreds of objects and they are stored in the memory. It is usually not a problem for a desktop application to load a few seconds before you can use it. But in PHP you initialize your application with every page request and it gets lost a fraction of a second later. Instantiating all application objects every time may quickly eat your server resources, especially if you need to serve tens or hundreds requests per second. So we usually want to instantiate only those objects which are needed and with this task a container (like a factory or DIC) can help - then depending on what a page request is supposed to do the application picks the needed objects from the container and executes proper methods.
Also, I think good dependency injection containers in PHP are a bit different from what he says is used in the Java world. It is not a map of objects but for the most part a clever mechanism that will infer the dependencies from the constructor parameters and create the objects, for example this same class as earlier:
class BlogController {
private $blogModel;
private $templateEngine;
public function __construct(BlogModel $blogModel, TemplateEngine $templateEngine) {
$this->blogModel = $blogModel;
$this->templateEngine = $templateEngine;
}
// ...
}
The container by using reflection knows that the necessary dependencies are BlogModel and TemplateEngine and can therefore create them automatically. So when you need an instance of BlogController you only need to do:
$blogController = $container->getInstance('BlogController');
and the container will do its magic and instantiate the object and you don’t have to define your own method to instantiate BlogController like we had to do when using a factory.
Personally, I haven’t used a DIC apart from the simplistic Pimple. I prefer a container in the form of a factory like I showed in my previous post. It may be slightly more work to write a method to instantiate a new object every time it’s needed but it’s really not much work and the advantage is the code is less magical, it’s clearer, I get IDE hints and gain a bit of performance. Anyway, the majority of your application should not deal with the container at all - it should use DI to require objects. The container is just used in the outer shell of your application to instantiate needed objects and then you don’t use it at all and you don’t pass it anywhere else. I think the deleted guy in this reddit thread has a point here.
The interesting thing I’ve observed in OOP that may seem daunting at first is that OOP solves a bunch of big problems but introduces a bunch small problems and then people invent solutions to these small problems, mostly trying to automate things in the long run. Like in this topic, when using static methods we don’t have to instantiate objects so naturally we don’t have a problem with that. Then we start using OO with DI, which helps a lot with the code readability but then we come up with a problem of object instantiation. So we invent a factory and use that. Then we think that maybe there’s too much manual work with the factory so we invent a DIC, which automates most of what the factory does. And it goes on and on. Large frameworks will often implement many of such tools automating frequent tasks and lessening the required amount of code to write and these tools may often require configurations in XML, yaml, or whatever, or PHP annotations or require us to follow some other set of conventions.
But each of such automation solutions comes with a drawback - it increases complexity (even if it’s hidden) and requires the programmer to learn specific framework configurations and conventions to be able to write and understand the code. This matter is purely subjective and every programmer may have different opinions on how far such solutions are helpful.
Personally, I favour code readability over succinctness. I prefer to read and write a bit more code that is immediately obvious what it does rather than have a code as short as possible but have to spend some time learning how to follow it. That’s why I think a full-fledged DIC does not bring enough benefits when I contrast it with how small a problem it solves relative to a factory but at the same time brings some hidden magic to the code - and a DIC also needs a bit of configuration so it not a fully automated thing. I think good code is code that a strange programmer can easily follow without knowing my framework and without having to read any documentation.