Service Container in Laravel
The Laravel Service Container (or IoC Container) is a powerful tool for managing class dependencies and performing dependency injection. It's one of Laravel's core features that enables its modular architecture.
Key Concepts
1. What is the Service Container?
A dependency injection container that manages class dependencies
Central registry for application services
Handles automatic dependency resolution
Implements Inversion of Control (IoC) principle
2. Basic Binding
Simple Binding
$this->app->bind('HelpSpot\API', function ($app) { return new HelpSpot\API($app->make('HttpClient')); });
Singleton Binding
$this->app->singleton('HelpSpot\API', function ($app) { return new HelpSpot\API($app->make('HttpClient')); });
Instance Binding
$api = new HelpSpot\API(new HttpClient); $this->app->instance('HelpSpot\API', $api);
3. Binding Interfaces to Implementations
$this->app->bind( 'App\Contracts\EventPusher', 'App\Services\RedisEventPusher' );
4. Contextual Binding
$this->app->when('App\Http\Controllers\PhotoController') ->needs('App\Contracts\ImageProcessor') ->give('App\Services\JpegImageProcessor');
Resolving from the Container
1. Using make()
$api = $this->app->make('HelpSpot\API');
2. Automatic Injection
class UserController extends Controller { public function __construct(HelpSpot\API $api) { $this->api = $api; } }
3. Using app()
Helper
$api = app('HelpSpot\API');
Practical Examples
1. Service Provider Registration
// In a Service Provider public function register() { $this->app->singleton(StripePaymentGateway::class, function () { return new StripePaymentGateway(config('services.stripe.secret')); }); }
2. Interface Binding
$this->app->bind( PaymentGatewayInterface::class, StripePaymentGateway::class );
3. Tagging Services
$this->app->tag([ SpeedReport::class, MemoryReport::class, ], 'reports');
Advanced Features
1. Extending Bindings
$this->app->extend(Service::class, function ($service, $app) { return new DecoratedService($service); });
2. Method Injection
public function store(Request $request, PaymentGateway $gateway) { $gateway->charge($request->amount); }
3. Container Events
$this->app->resolving(function ($object, $app) { // Called when container resolves any type of object }); $this->app->resolving(Logger::class, function ($logger, $app) { // Called when container resolves Logger specifically });
When to Use the Service Container
Dependency Injection: When your class has dependencies
Switching Implementations: When you want to easily swap implementations
Shared Instances: When you need singleton behavior
Complex Initialization: When object creation requires complex logic
Testing: When you need to mock dependencies
Best Practices
Prefer constructor injection over method injection for required dependencies
Use interfaces for important contracts in your application
Keep binding logic in service providers
Avoid service location (calling
app()
directly) when possibleDocument your bindings in complex applications