
Let's say you're writing an API service. You need this API to be highly available, distributed, fast... the requirements are several pages long. The problem with API calls is, that one call might not use the same cache objects as another, uses different data sources due to partitioning or other technical reasons.
A typical PHP programmer might just create an instance of every cache class, database class and others he might need. This way typical PHP applications end up creating objects which are never used during the course of execution. You can make some assumptions that optimize a few of these cases away, but you usually have overhead.
Your API service needs to be fast. I'm trying to keep everything below 10ms, with access to data from SQL databases and cache servers. Connecting to them takes time. I usually don't hit the 10ms goal without bypassing PHP altogether. My (old but current) API layer currently pushes everything out at 22ms and 30ms, at the 50th and 95th percentile.
You live you learn - I instantiate database objects and cache objects and things I don't need which take up valuable time from creating and using only what you need. So:
- I needed a way to create and connect only to those services I actually need to run. If I only need to connect to Redis, I don’t need to connect to MySQL as well.
- Leverage PHP language constructs to this end. Injecting dependencies should be language driven, not programmer driven.
I want you to think about this. Language driven vs. programmer driven - this is the main point. When it comes to programmer driven dependency injection, it will happen that your programmer(s) will be using their time writing methods that will get, set and report missing dependencies. It is a flawed concept from the beginning, as it introduces human error into the equation.
The programmer can and will forget to pass a dependency into an object causing a fatal error which doesn’t trigger an exception that could be caught. The problems mount - the programmer requires attention to detail and discipline, and uses his time writing boiler plate code instead of developing new features.
You can reduce this risk by implementing your dependencies as language driven constructs. PHP 5.4 introduced traits that could be leveraged to infer dependencies to be injected into objects, after they are instantiated. A typical execution flow would then be: