With dynamic scoping, when you need a DatabaseConnection, someone up the stack from you still has to construct it manually. With dependency injection, the framework can construct it for you.
I think maybe a better analogy for dependency injection is imports. When library A imports library B which imports library C, they can just declare that, nobody needs to assemble "new A(new B(new C()))". Dependency injection is the same thing, but instead of libraries you have stateful objects, like "a RequestHandler needs a RequestContext which needs a DatabaseConnection". Maybe these tasks could even be handled by the same tool, but I haven't seen such a tool yet.
I think maybe a better analogy for dependency injection is imports. When library A imports library B which imports library C, they can just declare that, nobody needs to assemble "new A(new B(new C()))". Dependency injection is the same thing, but instead of libraries you have stateful objects, like "a RequestHandler needs a RequestContext which needs a DatabaseConnection". Maybe these tasks could even be handled by the same tool, but I haven't seen such a tool yet.