Let’s move on to the examples.

I wanted to give the same example as in the previous article of mine.

Let’s say you want to send notifications to registered users for your e-commerce site to inform them about the campaigns. Let’s create a notification class and email service class for this.

class emailService

{

function send($message)

{

echo $message;

}

} class notification

{ function notify($message)

{

$EmailService = new emailService();

$EmailService->send($message);

}



} $notification = new notification();

$notification->notify("30% discount on all products");

Ok now there is no problem but the notification class is dependent on the email service class. So whenever I make a change to the email service class, I may need to update the notification class accordingly. This may be trouble in larger projects.

Then you decided to send SMS, you can create a new function and try it, but you need a better solution because this may not come to an end. If you want to delete the code and change it according to the SMS you should not delete it because you may have used this code in other parts of the code you wrote.

We want to add new services to the EmailService class, but the notification class must be independent of these changes in order not to make continuous changes to the notification class. That’s why we use the Dependency Injection design.

Let’s continue looking at the example

1.Constructor injection



Here we will inject our service while lifting the class up with the construct method.

interface serviceInterface

{

public function send($message);

}



class emailService implements serviceInterface

{

function send($message)

{

echo $message;

}

}





class notification

{



private $service; public function __construct(serviceInterface $service)

{

$this->service = $service;

}



public function send($message)

{

$this->service->send($message);

}



}



$emailService = new emailService();

$emailNotification = new notification($emailService);

$emailNotification->send("30% discount on all products");

Note: The reason the __construct method accepts only serviceInterface is because we want to ensure that $service is the send() method.

Now, it looks good. We have reduced the dependency of our notification class. It minds its own business. Since it needs service for it to work, we add our service via __construct method. And once the object has formed, we have made the service immutable throughout its lifetime.

2. Setter injection

interface serviceInterface

{

public function send($message);

}



class emailService implements serviceInterface

{

function send($message)

{

echo $message;

}

}



class notification

{



private $service;

private $message;



public function setService(serviceInterface $service)

{

$this->service = $service;

}



public function setMessage($message)

{

$this->message = $message;

}



public function send(){

$this->service->send($this->message);

}



}





$emailNotification = new notification();

$emailService = new emailService();

$emailNotification->setService($emailService);

$emailNotification->setMessage("30% discount on all products");

$emailNotification->send();

Now we can add all dependencies as much as we want, but there are downsides., if we forget to set the service, it will fail. Therefore, it is used more in optional dependencies. We cannot be sure that the service or message does not change over the life of the object.

If there are many dependencies, even with Constructor injection, it is a bit difficult to manage all this manually. This is one of the reasons why responsibility is transfer to the Framework.

3. Property Injection

interface serviceInterface

{

public function send($message);

}



class emailService implements serviceInterface

{

function send($message)

{

echo $message;

}

}



class notification

{



public $service;

public $message;



public function send()

{

$this->service->send($this->message);

}



}



$emailNotification = new notification();

$emailService = new emailService();

$emailNotification->service = $emailService;

$emailNotification->message = "30% discount on all products";

$emailNotification->send();

We can inject dependencies by making the variables public. But this can make our job difficult. Example: we cannot use type hinting.

Add new service

interface serviceInterface

{

public function send($message);

}



class emailService implements serviceInterface

{

function send($message)

{

echo $message;

}

}



class smsService implements serviceInterface

{

function send($message)

{

echo $message;

}

}



class notification

{



private $service;

private $message;



public function setService(serviceInterface $service)

{

$this->service = $service;

}



public function setMessage($message)

{

$this->message = $message;

}



public function send()

{

$this->service->send($this->message);

}



}





$notification = new notification();



$notification->setService(new emailService());

$notification->setMessage("30% discount on all products (EMAIL)");

$notification->send();





$notification->setService(new smsService());

$notification->setMessage("30% discount on all products (SMS)");

$notification->send();

We have added our smsService with peace of mind and our notification class is not interested in what is coming or even knows. We threw away all our dependencies and saved them from their burdens.

Take care of yourself until my next post :)