
How to Use Laravel Service Container and Dependency Injection Easily
If you are building bigger projects with Laravel, understanding the Service Container and Dependency Injection is very important. In this blog, we will explain these two important concepts in simple words and show you how they can make your Laravel 12 apps cleaner, faster, and easier to manage.
What is the Laravel Service Container?
In simple terms, the Service Container is a powerful tool that Laravel uses to manage class dependencies and perform dependency injection automatically.
Imagine the Service Container as a "smart box" that knows how to create and provide the objects your application needs — whenever you need them.
Instead of manually creating instances like this:
$userService = new UserService(new NotificationService());
Laravel can resolve them for you automatically.
What is Dependency Injection?
Dependency Injection (DI) is a design pattern where a class receives its dependencies from the outside, rather than creating them inside the class.
Example without Dependency Injection:
class OrderService {
public function __construct() {
$this->paymentGateway = new StripePaymentGateway();
}
}
Example with Dependency Injection:
class OrderService {
protected $paymentGateway;
public function __construct(PaymentGatewayInterface $paymentGateway) {
$this->paymentGateway = $paymentGateway;
}
}
Notice that with Dependency Injection, OrderService
doesn't care which payment gateway it gets — it just expects one that follows a contract (interface).
This approach leads to more flexible, testable, and decoupled code.
How Laravel’s Service Container Handles Dependency Injection
Laravel automatically uses the Service Container behind the scenes whenever it sees a class or interface typed in a controller or constructor.
namespace App\Http\Controllers;
use App\Services\OrderService;
class OrderController extends Controller
{
protected $orderService;
public function __construct(OrderService $orderService)
{
$this->orderService = $orderService;
}
public function store()
{
return $this->orderService->placeOrder();
}
}
Here, Laravel sees that OrderController
needs an OrderService
.
It resolves and injects the OrderService
automatically when the controller is instantiated.
Binding Things Manually to the Service Container
Sometimes, you need manual bindings, especially when dealing with interfaces or custom implementations.
You can bind services in a Service Provider
(commonly in App\Providers\AppServiceProvider):
use App\Services\PaymentGatewayInterface;
use App\Services\StripePaymentGateway;
public function register()
{
$this->app->bind(PaymentGatewayInterface::class, StripePaymentGateway::class);
}
Now, whenever Laravel sees PaymentGatewayInterface
, it will resolve a StripePaymentGateway!
.
Practical Example: Building a Payment Service
Let's say you have multiple payment gateways (Stripe, PayPal).
1 - Create an interface:
namespace App\Services;
interface PaymentGatewayInterface
{
public function charge($amount);
}
2 - Create an implementation:
namespace App\Services;
class StripePaymentGateway implements PaymentGatewayInterface
{
public function charge($amount)
{
// Stripe charging logic
}
}
3 - Bind it in the container:
public function register()
{
$this->app->bind(PaymentGatewayInterface::class, StripePaymentGateway::class);
}
3 - Inject it anywhere:
class BillingController extends Controller
{
public function __construct(protected PaymentGatewayInterface $paymentGateway) {}
public function chargeCustomer()
{
$this->paymentGateway->charge(100);
}
}
Understanding the Service Container
and Dependency Injection in Laravel
unlocks a higher level of flexibility and power in your applications.