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)
Sign in to submit a comment