Dependency Injection in PHP simply explained with an example
Published: 2024-05-26 19:39:19

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.