DI containers, when used wrong, i.e., in most cases, are not just , but the absolute evil. code polluters It’s a static dependency DI containers are very often called from all over the place. DI container in this case is just a , which is a singleton. Singleton with huge amount of methods. Besides that it introduces . That’s how it might look like: service locator hidden dependencies PaymentProcessor{ purchase(){ DIPaymentModuleFactory:: ()->purchase();}} class public function return me To remedy this mistake, the only way is to use it only on the highest level of an application, preferably in index file where an application starts. And if you’d use it that way — do you really still need it? You don’t anyway. It’s already, and there are two more points ahead. Catch-22 It breaks one of the most solid OOP metaphors DI container breaks the metaphor of a that David West talks about in his book . I want my classes to be instantiated in a single place, and this place should be an entry point of any request or message. Their collaboration should be achieved only with composition. And composability is the goal that any aspiring object-thinker is striving for. Lego brick Object Thinking It breaks cohesion Moreover, it breaks fundamental OOP principles — data encapsulation and exposing behavior instead. Why the way an object should be instantiated is hidden to the program code? Why is it put in some ? Really, think about it — it’s nonsense! This point is even broader. Why do we ever need a config file? Why is some piece of data torn apart of its behavior? This is exactly what talked about 14 years ago, right? And everyone seems to agree with that. But why do we keep following this concept? Configuration files are just reflective of a procedural mindset! configuration file Martin Fowler Life without DI-container It’s a . So that’s how my entry point usually looks like: pure Dependency Injection { ( PurchaseOrder( LocalOrderStorage( NullOrderStorage()), OrderId($inputParams[ ])))->newInvoice( InvoiceNumber( Vendor( LocalVendorStorage(), VendorId($inputParams[ ])), VendorInvoiceNumber($inputParams[ ]), DateTime($inputParams[ ])), VendorInvoiceNumber($inputParams[ ]), DateTime($inputParams[ ]), InvoiceAmount( Amount($inputParams[ ]), Currency($inputParams[ ])))->json();} (Exxeption $exxeption) { ( ErrorResult())->json($exxeption->getCode(), $exxeption->getMessage());} try echo new new new new 'order_id' new new new new 'vendor_id' new 'vendor_invoice_number' new 'date_time' new 'vendor_invoice_number' new 'date_time' new new 'amount' new 'currency' catch return new It’s wonderful. Join me.