Table of contents
Definition
Dependency injection as a concept is similar to the difference between getting your coffee already made for you versus getting a cup of coffee with sugar and cream on the side.
In the latter example, you get to decide how much sugar and cream to use or even forego them altogether.
Dependency injection is similar to the latter where you get to decide or be able to swap out other code your original piece of code depends on.
Example
Without dependency injection
01: <?php
02:
03: class PaymentProcessor {
04: public function charge($price) {
05: return "charged customer: ".$price;
06: }
07: }
08:
09: class CheckOut {
10:
11: private $processor;
12:
13: public function __construct() {
14: $this->processor = new PaymentProcessor();
15: }
16:
17: public function makePayment($price) {
18: return $this->processor->charge($price);
19: }
20: }
21:
22: $checkout = new CheckOut();
23: echo $checkout->makePayment(200);
24: ?>
The sample code above shows two classes PaymentProcessor
and CheckOut
. The CheckOut
class depends on the PaymentProcessor
class to process payments.
As part of the definition of the CheckOut
class it creates an instance of the PaymentProcessor
class internally and assigns it to the $processor
property (line:14)
to later be used in the makePayment
method.
In the above example, anyone using the CheckOut
class has very little control over the type of PaymentProcessor
used as it is internal to the CheckOut
class.
Using dependency injection
01: <?php
02: class PaymentProcessor {
03: public function charge($price) {
04: return "charged customer: ".$price;
05: }
06: }
07:
08: class CheckOut {
09:
10: private $processor;
11:
12: public function __construct(PaymentProcessor $processor) {
13: $this->processor = $processor;
14: }
15:
16: public function makePayment($price) {
17: return $this->processor->charge($price);
18: }
19: }
20: $processor = new PaymentProcessor();
21: $checkout = new CheckOut($processor);
22: echo $checkout->makePayment(200);
23: ?>
In the second example we see the constructor __construct
now requires the user of the CheckOut
class to pass in the PaymentProcessor
themselves. This allows them to use other payment processors [→]
On line 19
we now instantiate our PaymentProcessor
separately and then pass it into the CheckOut
class on line 20
.
Summary
The key concept is our ability to swap out different dependencies in our code. This provides some benefits such as being able to swap out providers and also swap out code during testing, to avoid making non-idempotent [↗] changes.
Here is another article you might like 😊 What are namespaces?