Categories
Design Pattern Programming

DI (Dependency Injection) in PHP

There are a few similar terms in the programming world like HTML injection, SQL injection, etc.

What does DI mean?

Dependency Injection is a design pattern that helps avoid hard-coded dependencies for classes.

Let’s try to make it clear using a simple Shopping Cart Example

<?php

class Car
{
    public function buy()
    {
        return true;
    }
}

class MotorBike
{
    public function buy()
    {
        return true;
    }
}

class Cart
{
    protected $vehicle;
    public function __construct(Car $vehicle)
    {
        $this->vehicle = $vehicle;
    }

    public function proceed()
    {
        return $this->vehicle->buy();
    }
}

$cart = new Cart(new Car());
$cart->proceed();

Suppose, You have an online shop and there are 2 products (Car & MotorBike). So you may write code like the above example.

Is there anything wrong with the above example?

Nothing is wrong here. Everything is fine and workable code to purchase Car.

Question: How can you buy a Motorbike?

Answer: It’s very simple. Just Change the Cart Class __construct() function like below.


    public function __construct(MotorBike $vehicle)
    {
        $this->vehicle = $vehicle;
    }

And Initiate the class like below.


$cart = new Cart(new MotorBike());
$cart->proceed();

It works !!!

But the Cart Class depends on the Car/Motorbike class. You resolved this dependency by changing the Cart class constructor.

It violates the Solid Principle (A philosophy of making OOD object-oriented design) by Robert C. Martin.

S - Single-responsiblity Principle
O - Open-closed Principle
L - Liskov Substitution Principle
I - Interface Segregation Principle
D - Dependency Inversion Principle

He is also known as uncle BOB.

Eventually, it violates the Open-closed Principle. That means you can extend your class but you can’t modify it. But you already did that.

What will happen if we can resolve this dependency automatically? This concept is called Dependency Injection.

Let’s try to inject the Class Dependency to the Cart Class Constructor using the power of OOP.

<?php

interface Vehicle
{
    public function buy();
}

class Car implements Vehicle
{
    public function buy()
    {
        return true;
    }
}

class MotorBike implements Vehicle
{
    public function buy()
    {
        return true;
    }
}

class Cart
{
    protected $vehicle;
    public function __construct(Vehicle $vehicle)
    {
        $this->vehicle = $vehicle;
    }

    public function proceed()
    {
        return $this->vehicle->buy();
    }
}

$cart = new Cart(new MotorBike());
$cart->proceed();

$cart = new Cart(new Car());
$cart->proceed();

Check the example above. You can Add Car/Motorbike without modifying your Cart class.

I made an abstraction Layer (Vehicle) of the Lower Module (Car/Motorbike Class) and Changed the Higher Module (Cart Class) Constructor Parameter type to that Abstraction layer.

All (Higher Module & Lower Module ) depends on Vehicle, not each other.

This is known as DI (Dependency Injection)