>I wonder: Is automatic DI even helpful? You save some lines of boilerplate but sacrifice control over the initialization-order and get a flat, messy, implicit dependency graph
Initialization order doesn't matter if your services are stateless. At least in our codebase, all of them are stateless, as it greatly simplifies reasoning about concurrent code (both in-process and between servers). Yes, it's easy to end up with a very convoluted dependency graph under the hood, but I don't think it's a problem you really should care about. I mean, your code most likely already compiles to a very convoluted mess of machine code under the hood (with all the optimizations, ABI quirks etc.) and I doubt it matters to you much, as long as it does its job well and doesn't hinder your productivity.
If you are talking about messy dependency graphs from the architectural standpoint (someone can easily add a dependency in the constructor without thinking about the consequences), we use deptrac for our PHP monolith which can validate your architecture is clean at build time [0]
However, for our microservices written in Go, we decided to use manual DI to stimulate developers to prefer simpler design, otherwise our microservices could quickly turn into monoliths again.
[0] https://github.com/qossmic/deptrac