Lesson 4
Dependency Injection in Laravel
Dependency Injection in Laravel

Welcome back to your Laravel learning journey! As we venture deeper into Laravel, you’ll now learn about a crucial concept known as Dependency Injection. Building on the idea of services from the previous lesson, Dependency Injection will help you understand how Laravel's design encourages clean and efficient coding. This lesson is designed to help you grasp this important concept and see how it can simplify the dependencies within your application.

What You'll Learn

In this lesson, you will understand what Dependency Injection is and how it functions within a Laravel application. We'll explore real-world examples to demonstrate how it plays a key role in creating dynamic and modular applications. Specifically, you'll learn how to inject dependencies into your services and controllers, promoting clean and manageable code.

Here is a concise example that expands on our previous lesson, where you will see an ExampleService dependent on BreadProvider, CheeseProvider, and GrillProvider, all injected into the ExampleService using Dependency Injection.

app/app/Services/ExampleService.php

php
1<?php 2 3namespace App\Services; 4 5use App\Providers\BreadProvider; 6use App\Providers\CheeseProvider; 7use App\Providers\GrillProvider; 8 9class ExampleService 10{ 11 protected $bread; 12 protected $cheese; 13 protected $grill; 14 15 public function __construct(BreadProvider $bread, CheeseProvider $cheese, GrillProvider $grill) 16 { 17 $this->bread = $bread; 18 $this->cheese = $cheese; 19 $this->grill = $grill; 20 } 21 22 public function makeSandwich() 23 { 24 $this->grill->turnOn(); 25 $sandwich = "Sandwich with " . $this->bread->getName() . " and " . $this->cheese->getName(); 26 $this->grill->turnOff(); 27 return $sandwich; 28 } 29}

Let's understand the code above:

  • The ExampleService class has three properties: $bread, $cheese, and $grill.
  • The __construct method injects the dependencies BreadProvider, CheeseProvider, and GrillProvider into the ExampleService.
  • The makeSandwich method uses the injected dependencies to create a sandwich with bread and cheese, turning the grill on and off in the process. Finally returning the sandwich.

Now let's see how we should define the BreadProvider, CheeseProvider with a common interface IngredientInterface and the GrillProvider class.

First, let's define the IngredientInterface interface. Interfaces are contracts that define the methods a class must implement. In this case, the IngredientInterface interface has a single method getName, which means any class that implements this interface must have a getName method.

app/app/Providers/IngredientInterface.php

php
1<?php 2 3namespace App\Interfaces; 4 5interface IngredientInterface 6{ 7 public function getName(); 8}

Next, let's define the concrete classes BreadProvider, CheeseProvider that implement the IngredientInterface interface.

app/app/Providers/BreadProvider.php

php
1<?php 2namespace App\Providers; 3use App\Interfaces\IngredientInterface; 4 5class BreadProvider implements IngredientInterface 6{ 7 public function getName() 8 { 9 return "Slice of Bread"; 10 } 11}

app/app/Providers/CheeseProvider.php

php
1<?php 2namespace App\Providers; 3use App\Interfaces\IngredientInterface; 4 5class CheeseProvider implements IngredientInterface 6{ 7 public function getName() 8 { 9 return "Cheese"; 10 } 11}

Finally, let's define the GrillProvider class. Note that this class does not implement the IngredientInterface interface, as it is not an ingredient.

app/app/Providers/GrillProvider.php

php
1<?php 2 3namespace App\Providers; 4 5class GrillProvider 6{ 7 public function turnOn() 8 { 9 echo 'Grill is turned on.'; // echo prints the message to the browser directly 10 } 11 12 public function turnOff() 13 { 14 echo 'Grill is turned off.'; 15 } 16}

In the code above, we have defined the IngredientInterface interface, which is implemented by the BreadProvider and CheeseProvider classes. The GrillProvider class does not implement the IngredientInterface interface, as it is not an ingredient. The ExampleService class injects the BreadProvider, CheeseProvider, and GrillProvider classes using Dependency Injection.

Now, it's time to see how we can use the ExampleService class in a controller:

app/app/Http/Controllers/ExampleController.php

php
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Services\ExampleService; 6use Illuminate\Http\Request; 7 8class ExampleController extends Controller 9{ 10 protected $exampleService; 11 12 public function __construct(ExampleService $exampleService) 13 { 14 $this->exampleService = $exampleService; 15 } 16 17 public function makeSandwich() 18 { 19 $sandwich = $this->exampleService->makeSandwich(); 20 return view('sandwich', ['sandwich' => $sandwich]); 21 } 22}

In the ExampleController class, the ExampleService class is injected into the controller using Dependency Injection. The makeSandwich method calls the makeSandwich method of the ExampleService class and returns the result to a view.

Finally, we'll add a route to the routes/web.php file to access the makeSandwich method of the ExampleController class, and display the sandwich in a view.

As a result, when you access the route, you will see the sandwich created by the ExampleService class using the injected dependencies, and the following message will be displayed in the browser:

Plain text
1Grill is turned on. Grill is turned off. 2Sandwich with Slice of Bread and Cheese

Note, that the grill related messages are printed directly to the browser using the echo statement. In a real-world application, you would typically return the messages as a response to the client.

In this example, we have seen how Dependency Injection can be used to inject dependencies into classes, promoting clean and manageable code. By injecting dependencies instead of hardcoding them, you create flexible applications that are easier to debug and extend.

Why It Matters

Dependency Injection is a cornerstone of modern software development and is particularly important when working with Laravel. It promotes loose coupling between classes, making your code easier to test and maintain. By injecting dependencies instead of hardcoding them, you create flexible applications that are easier to debug and extend.

Learning Dependency Injection ensures you can build more scalable and resilient applications. It helps you adhere to solid design principles that are critical in building applications that stand the test of time.

Are you eager to see how Dependency Injection will transform your approach to coding in Laravel? Let's move to the practice section to get hands-on experience with these concepts.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.