Lesson 43 of 50
The Laravel Service Container is a tool that manages class dependencies and helps Laravel create objects when they are needed.
When one class requires another class to perform its work, the service container can resolve and provide that dependency.
Example:
Suppose a student controller needs a service to generate student reports. Instead of creating that service manually inside the controller, Laravel can inject it automatically.
Benefits:
Dependency Injection (DI) means providing a class with the objects it needs instead of making the class create those objects itself.
Without dependency injection:
<?php
class StudentReport
{
public function generate(): string
{
return 'Student report generated.';
}
}
class StudentController
{
public function showReport(): string
{
$report = new StudentReport();
return $report->generate();
}
}
Here, the controller creates the
StudentReport object directly.
With dependency injection:
<?php
class StudentReport
{
public function generate(): string
{
return 'Student report generated.';
}
}
class StudentController
{
public function __construct(
private StudentReport $report
) {}
public function showReport(): string
{
return $this->report->generate();
}
}
Laravel can resolve the concrete
StudentReport class and inject it into
the controller constructor.
Create a service class:
app/Services/StudentReportService.php
Example service code:
<?php
namespace App\Services;
class StudentReportService
{
public function generate(): string
{
return 'Student report generated successfully.';
}
}
Now create a controller:
php artisan make:controller StudentReportController
Open the controller:
<?php
namespace App\Http\Controllers;
use App\Services\StudentReportService;
class StudentReportController extends Controller
{
public function __construct(
private StudentReportService $reportService
) {}
public function index()
{
$message = $this->reportService->generate();
return response()->json([
'message' => $message,
]);
}
}
Laravel automatically resolves this concrete service class when constructing the controller, provided its dependencies can also be resolved.
Explicit container bindings are not normally required for simple concrete classes like this one.
Laravel can also inject dependencies directly into controller methods.
<?php
namespace App\Http\Controllers;
use App\Services\StudentReportService;
class StudentReportController extends Controller
{
public function index(
StudentReportService $reportService
) {
return response()->json([
'message' => $reportService->generate(),
]);
}
}
Laravel resolves the service and passes it to the controller method when handling the request.
Register a route in routes/web.php:
use App\Http\Controllers\StudentReportController;
use Illuminate\Support\Facades\Route;
Route::get(
'/student-report',
[StudentReportController::class, 'index']
);
Visit:
http://127.0.0.1:8000/student-report
Example JSON response:
{
"message": "Student report generated successfully."
}
Sometimes a class depends on an interface rather than a specific implementation. In that situation, you can register a binding that tells Laravel which class to use.
Create an interface:
app/Contracts/ReportGenerator.php
<?php
namespace App\Contracts;
interface ReportGenerator
{
public function generate(): string;
}
Create an implementation:
app/Services/StudentReportService.php
<?php
namespace App\Services;
use App\Contracts\ReportGenerator;
class StudentReportService implements ReportGenerator
{
public function generate(): string
{
return 'Student report generated successfully.';
}
}
Register the interface-to-class binding in
app/Providers/AppServiceProvider.php.
use App\Contracts\ReportGenerator;
use App\Services\StudentReportService;
public function register(): void
{
$this->app->bind(
ReportGenerator::class,
StudentReportService::class
);
}
Keep the existing provider class and methods. Add the
imports at the top and place the binding inside its
register() method.
Now Laravel knows which implementation to provide
whenever a class requests the
ReportGenerator interface.
Once the interface binding is registered, you can inject the interface instead of the concrete service.
<?php
namespace App\Http\Controllers;
use App\Contracts\ReportGenerator;
class StudentReportController extends Controller
{
public function index(ReportGenerator $reportGenerator)
{
return response()->json([
'message' => $reportGenerator->generate(),
]);
}
}
Why is this useful?
Laravel uses the binding registered in the service provider to resolve the interface.
You can resolve a dependency from the service container when you need an object outside normal controller dependency injection.
Using the app() helper:
use App\Services\StudentReportService;
$reportService = app(StudentReportService::class);
$message = $reportService->generate();
echo $message;
You can also use the container facade:
use Illuminate\Support\Facades\App;
use App\Services\StudentReportService;
$reportService = App::make(
StudentReportService::class
);
echo $reportService->generate();
Both examples ask Laravel's container to resolve the service class and its resolvable dependencies.
Prefer constructor or method injection for ordinary application code. Manual resolution is useful when dependencies must be obtained dynamically or outside Laravel's normal injection points.
Remember:
Dependency injection is a programming technique. The Laravel service container is the mechanism that helps resolve and supply dependencies in a Laravel application.
Build a small report-generation system.
ReportGenerator interface.StudentReportService implementation.Bonus Task:
Create a FeeReportGenerator interface with
separate implementations for monthly and yearly fee
reports. Use container bindings to choose the
implementation.
1. What is the main purpose of Laravel's service container?
2. What does dependency injection mean?
3. Where can you register an interface binding in Laravel?