No, you don’t need a full-feature Dependency Injection framework or huge XML configuration files to have dependency injection. Annotations are nice, and having an automated container makes life easier, but that’s not what makes this design pattern what it is. The principle behind inversion of control is as simple as a constructor or method call.
Dependency injection, sometimes referred to as DI, is a technique used in software development in order to simplify code and decouple components it uses.
Some of the benefits of dependency injection are code that’s easier to test, code that fails independently, flexibility, and maintainability.
Generally speaking, any time you have a new statement inside one of your structures, where a new object is instantiated, you have a great candidate for dependency injection.
Someone in the comments brought up the idea of using factories instead of dependency injection, so that the dependencies are outside the client (through the factory class). Remember, though, that at the end of the day, someone, somewhere needs to specify the concrete detail that will make the application run. One approach is to use a factory class that uses dependency injection. The 2 principles are not mutually exclusive. Keep in mind that one of the key benefits to using DI, though, is that it makes testing much easier (or looking at the way some PHP developers write their code — it makes testing possible).
Imagine unit testing a class that depends on a factory whose dependencies are hard coded… through dependency injection, you can inject a mock factory inside your unit test, or configure the factory to return mocks.
Dependency Injection is not only a good subject for an “advanced PHP tutorial”, but is an important concept in good software design (or object-oriented design and analysis). Think of it in terms of writing quality, maintainable, and testable code.