Dependency Injection in PHP simply explained with an example

RMAG news

I think you all have heard about Dependency Injection in PHP. But do you know it well?. If not read this and you will understand.

Example Without Dependency Injection

First let us talk about example without Dependency Injection. Then let us talk about drawbacks and let’s talk how to overcome them with Dependency Injection

We need these two classes

class Vehicle {
private $make;
private $model;

public function __construct($make, $model){
$this->make = $make;
$this->model = $model;
}
}

class Garage {
private $vehicle;
private $sku;

public function __construct($sku, $vehicleMake, $vehicleModel){
$this->vehicle = new Vehicle($vehicleMake, $vehicleModel);
$this->sku = $sku;
}
}

Make note that we are calling Vehicle class inside Garage class and create an object.

But this approach may create problems. Imagine this scenario. Imagine we need to add subclass instead of main class. This is the subclass,

class ElectricVehicle extends Vehicle {
private $batteryCapacity;

public function __construct($make, $model, $batteryCapacity){
parent::__construct($make, $model);
$this->batteryCapacity = $batteryCapacity;
}

public function getBatteryCapacity() {
….
}
}

To use this new implementation, you need to modify the Garage class:

class Garage {
private $vehicle;
private $sku;

public function __construct($sku, $make, $model, $batteryCapacity = null){
if ($batteryCapacity) {
$this->vehicle = new ElectricVehicle($make, $model, $batteryCapacity);
} else {
$this->vehicle = new Vehicle($make, $model);
}
$this->sku = $sku;
}
}

This change introduces conditional logic inside the Garage class, making it more complex and harder to maintain. Every time a new type of Vehicle is added, the Garage class must be modified.

Improved Approach with Dependency Injection

To avoid these issues, you can use dependency injection to decouple the classes. Check this out,

class Vehicle {
private $make;
private $model;

public function __construct($make, $model){
$this->make = $make;
$this->model = $model;
}
}

class ElectricVehicle extends Vehicle {
private $batteryCapacity;

public function __construct($make, $model, $batteryCapacity){
parent::__construct($make, $model);
$this->batteryCapacity = $batteryCapacity;
}

public function getBatteryCapacity() {

}
}

class Garage {
private $vehicle;
private $sku;

public function __construct($sku, Vehicle $vehicle){
$this->vehicle = $vehicle;
$this->sku = $sku;
}
}

// Create an instance of Vehicle
$vehicle = new Vehicle(‘Toyota’, ‘Corolla’);
$garage = new Garage(‘SKU123’, $vehicle);

// Create an instance of ElectricVehicle
$electricVehicle = new ElectricVehicle(‘Tesla’, ‘Model S’, 100);
$electricGarage = new Garage(‘SKU124’, $electricVehicle);

Check this example very carefully. Let us simplify this. Imagine we have new requirement to get BatteryCapacity. Here we have created a subclass from parent class and added the function getBatteryCapacity(). Check that we haven’t change Vehicle or Garage class. This is the real power of Dependency Injection.