DI and property injection
Dependency Injection is the apparent passing of dependencies, i.e., each class openly claiming its dependencies instead of surreptitiously acquiring them from somewhere. What if dependencies were passed directly to variables? I'll discuss the pitfalls and benefits of property injection.
Property injection has one significant advantage: brevity. Compare:
class Foobar
{
/** @var HttpRequest */
private $httpRequest;
/** @var Router */
private $router;
function __construct(HttpRequest $httpRequest, Router $router)
{
$this->httpRequest = $httpRequest;
$this->router = $router;
}
}
vs.
class Foobar
{
/** @var HttpRequest @inject */
public $httpRequest;
/** @var Router @inject */
public $router;
}
We have to define variables anyway. Usually, we include an annotation
@var
and the corresponding data type. It is tempting to save
yourself the trouble and add a simple @inject
instead of writing
routine constructor or method code inject()
. In addition to minimal
code overhead, property injection neatly solves the problem of dependency
passing and inheritance.
Using annotation is another convention for passing dependencies. I emphasize the word other because whether we enumerate dependencies as method arguments or by annotating, it is an equivalent activity. It's not a container dependency, it's just a convention; after all, containers haven't been mentioned yet, and the examples make sense.
In the article on passing dependencies, I avoided using variables in a wide arc because they have serious shortcomings:
- public variables do not provide type checking
- public variables do not provide immutability
- private variables cannot be filled with any language construct
- private variables are not part of the public API – therefore they are not a dependency declaration!
- the disadvantages of both apply to protected variables
For properly property injection, we would need a read-only public variable with type checking. If PHP could do this, there would be nothing stopping us from using them.
(Update: PHP 8.1 already does this)
All parts:
- What is Dependency Injection?
- Dependency Injection versus Service Locator
- Dependency Injection and passing of dependencies
- Dependency Injection and property injection (you are currently reading)
- Dependency Injection versus Lazy loading
Sign in to submit a comment