The Power of Laravel’s Service Container: A Practical Guide

Balwant Singh
Simform Engineering
4 min readFeb 17, 2023

Learn how to leverage the Service Container to manage class dependencies in your Larevel application easily.

image credit to the respective owner

If you’ve been working with Laravel for a while, you may have heard of the Service Container. But what is it, and how can you use it to take your Laravel projects to the next level?

In this tutorial, we will thoroughly explore the Service Container tool and show you how to use it to manage class dependencies in your Laravel application. Let’s start with a simple example and gradually refactor it into a more advanced example to show you how to harness the full power of the Service Container.

Getting Started with a Simple Example

Let’s start by creating a new controller and injecting a specific class into it. We will use a payment gateway as an example of a typical scenario where you need to charge a customer’s credit card or bank account when they place an order on your website

  1. Create a controller by running the following command:
php artisan make:controller PayOrderController

2. Add a store() method to the controller and include a PaymentGateway dependency:

namespace App\Http\Controllers;

use App\Billing\PaymentGateway;

class PayOrderController extends Controller
{
public function store(PaymentGateway $paymentGateway)
{
// code to charge customer's account
}
}

3. Create a PaymentGateway class inside the app/Billing directory:

namespace App\Billing;

class PaymentGateway
{
public function charge($amount)
{
$bankResponse = [
'amount' => $amount,
'confirmation_number' => str_random(10),
];

return $bankResponse;
}
}

4. Now you can use the $paymentGateway object inside the store() method to charge the customer's account:

public function store(PaymentGateway $paymentGateway)
{
$amount = 2500; // $25.00
$bankResponse = $paymentGateway->charge($amount);

return view('receipt', [
'amount' => $bankResponse['amount'],
'confirmation_number' => $bankResponse['confirmation_number'],
]);
}

This is a simple example of how to use the Service Container tool in Laravel. However, as your project grows, you will find that managing class dependencies can become more complex. That’s when the Service Container really shines!

Advanced Application of the Service Container

Let’s take the above example and refactor it to utilize the Service Container more efficiently. We will use a ServiceProvider to register our PhonePayPaymentGateWay class, and add some additional functionality to demonstrate the flexibility of the Service Container.

credit to the respective image owner
  1. Create an PaymentGatewayInterface interface:
namespace App\Billing;

interface PaymentGatewayInterface
{
public function charge($amount);
}

2. Update the PhonePePaymentGateway class to implement the interface:

namespace App\Billing;

class PhonePePaymentGateway implements PaymentGatewayInterface
{
public function charge($amount){
#phone pe payment gateway payment charge api implemtation
}
}

3. Create a PaymentGatewayServiceProvider class inside the app/Providers directory:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Billing\PaymentGatewayInterface;
use App\Billing\PaymentGateway;

class PaymentGatewayServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(PaymentGatewayInterface::class, function ($app) {
return new PhonePePaymentGateway();
});
}
}

4. Add the PaymentGatewayServiceProvider to the providers array in your config/app.php file:

'providers' => [
// ...
App\Providers\PaymentGatewayServiceProvider
]

This registers the PaymentGatewayServiceProvider with Laravel, allowing it to use the Service Container to manage dependencies and inject instances of the PhonePePaymentGateway to a class where it’s needed.

Once you have added the provider, you can now access the PhonePePaymentGateway instance anywhere in your application by simply type-hinting it in the constructor of a class that needs it. For example:

namespace App\Http\Controllers;

use App\Services\PaymentGateway;

class PaymentController extends Controller
{
protected $paymentGateway;

public function __construct(PaymentGatewayInterface $paymentGateway)
{
$this->paymentGateway = $paymentGateway;
}

public function store()
{
// use the payment gateway to process the payment
$result = $this->paymentGateway->charge(2500);

// handle the payment result
}
}

In this example, we inject an instance of the PaymentGatewayInterface into the PaymentController constructor. This is possible because we have registered PaymentGatewayServiceProvider with Laravel, which tells it how to create instances of the PhonePePayementGateway class.

With this setup, we can easily swap the implementation of the PaymentGateway class with a different one simply by updating the PaymentGatewayServiceProvider.

credit to the respective owner

Here is an example of how to proceed if we need to swap payment gateway:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Billing\PaymentGatewayInterface;
use App\Billing\PaymentGateway;

class PaymentGatewayServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(PaymentGatewayInterface::class, function ($app) {
return new GooglePayPaymentGateway();
});
}
}

In this example, we are changing PaymentGatewayServiceProvider with a GooglePayPaymentGateway class.

And here is GooglePayPaymentGateway class:

namespace App\Billing;

class GooglePayPaymentGateway implements PaymentGatewayInterface
{
public function charge($amount){
#googlepay payment gateway payment charge api implemtation
}
}

We can implement the rest of the functionality in our PaymentController for charge will be the same as implement, and there is no need to change it.

This is the power of the Laravel Service Container and why it is such an important part of the framework!

Conclusion

Laravel’s Service Container is an essential and powerful tool for managing class dependencies in your application. By using the Service Container, you can easily define how your classes should be instantiated, and Laravel takes care of the rest. This not only simplifies your code but also makes it more modular and maintainable. I hope this article helped you get a good understanding of the Service Container’s basic principles and how to use them in your Laravel projects. As you continue working with Laravel, you will likely find more ways to take advantage of the Service Container and improve your application’s architecture.

Acknowledgments

I would like to thank the Laravel community and the Laravel documentation team for their invaluable contributions to the Laravel ecosystem.

Stay up to date with the latest trends in the development ecosystem by following Simform Engineering.

--

--

Balwant Singh
Simform Engineering

Software Engineer | Laravel | PHP | SQL | MySQL | Angular Js | jQuery | Database