Salta al contenuto principale
Laravel

Laravel Service Container: Dependency Injection Made Easy

Comprendi il Service Container di Laravel e come sfruttare la Dependency Injection per codice più testabile.

Giovanni D'Ippolito
3 min

Autore

Giovanni D'Ippolito

Pubblicato

11 November 2025

Tempo di lettura

3 minuti

Tags

#Laravel #Service Container #Dependency Injection #Design Patterns

Cos'è il Service Container?

Il Service Container è uno strumento potente per gestire le dipendenze delle classi e eseguire la dependency injection in Laravel.

Dependency Injection Base

Laravel risolve automaticamente le dipendenze nei controller:

<?php
namespace App\Http\Controllers;

use App\Services\PaymentService;
use App\Repositories\OrderRepository;

class OrderController extends Controller
{
    // Laravel inietta automaticamente le dipendenze
    public function __construct(
        protected PaymentService $paymentService,
        protected OrderRepository $orderRepository
    ) {}

    public function store(Request $request)
    {
        $order = $this->orderRepository->create($request->validated());
        $this->paymentService->process($order);

        return response()->json($order, 201);
    }
}
?>

Binding nel Service Container

Registra i tuoi servizi nel container:

<?php
// app/Providers/AppServiceProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Services\PaymentService;
use App\Services\StripePaymentService;
use App\Repositories\OrderRepository;
use App\Repositories\EloquentOrderRepository;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Binding semplice
        $this->app->bind(PaymentService::class, StripePaymentService::class);

        // Singleton - una sola istanza condivisa
        $this->app->singleton(OrderRepository::class, EloquentOrderRepository::class);

        // Binding con closure per logica complessa
        $this->app->bind(PaymentService::class, function ($app) {
            $gateway = config('services.payment.gateway');

            return match($gateway) {
                'stripe' => new StripePaymentService(),
                'paypal' => new PayPalPaymentService(),
                default => throw new \Exception('Invalid payment gateway'),
            };
        });
    }
}
?>
La differenza tra bind() e singleton() è che singleton crea una sola istanza riutilizzata, mentre bind crea una nuova istanza ogni volta.

Interfacce e Implementazioni

Programma verso interfacce per codice più flessibile:

<?php
// Interfaccia
namespace App\Contracts;

interface PaymentGateway
{
    public function charge(int $amount, string $currency): bool;
    public function refund(string $transactionId): bool;
}

// Implementazione Stripe
namespace App\Services;

use App\Contracts\PaymentGateway;

class StripePaymentGateway implements PaymentGateway
{
    public function charge(int $amount, string $currency): bool
    {
        // Logica Stripe
        return true;
    }

    public function refund(string $transactionId): bool
    {
        // Logica rimborso Stripe
        return true;
    }
}

// Implementazione PayPal
class PayPalPaymentGateway implements PaymentGateway
{
    public function charge(int $amount, string $currency): bool
    {
        // Logica PayPal
        return true;
    }

    public function refund(string $transactionId): bool
    {
        // Logica rimborso PayPal
        return true;
    }
}
?>

Registra l'interfaccia nel Service Provider:

<?php
// AppServiceProvider.php
public function register(): void
{
    $this->app->bind(
        \App\Contracts\PaymentGateway::class,
        \App\Services\StripePaymentGateway::class
    );
}
?>

Ora puoi usare l'interfaccia nei tuoi controller:

<?php
use App\Contracts\PaymentGateway;

class CheckoutController extends Controller
{
    public function __construct(
        protected PaymentGateway $paymentGateway
    ) {}

    public function process(Request $request)
    {
        // Funziona con qualsiasi implementazione!
        $success = $this->paymentGateway->charge(
            $request->amount,
            $request->currency
        );

        return response()->json(['success' => $success]);
    }
}
?>
Usando interfacce e il Service Container, puoi facilmente cambiare implementazione senza modificare il codice che le usa!

Vantaggi per i Test

La dependency injection rende il testing molto più semplice:

<?php
namespace Tests\Feature;

use Tests\TestCase;
use App\Contracts\PaymentGateway;
use Mockery;

class CheckoutTest extends TestCase
{
    public function test_checkout_process()
    {
        // Mock del payment gateway
        $mock = Mockery::mock(PaymentGateway::class);
        $mock->shouldReceive('charge')
            ->once()
            ->with(1000, 'EUR')
            ->andReturn(true);

        // Sostituisci nel container
        $this->app->instance(PaymentGateway::class, $mock);

        // Testa il controller
        $response = $this->postJson('/api/checkout', [
            'amount' => 1000,
            'currency' => 'EUR'
        ]);

        $response->assertJson(['success' => true]);
    }
}
?>

Condividi questo articolo

Articoli Correlati

Laravel

Laravel Eloquent: Query Optimization per Performance Migliori

Tecniche avanzate per ottimizzare le query Eloquent e migliorare le performance della tua applicazio...

03 Nov 2025 2 min
Leggi di più →
Laravel

Laravel Jobs e Queues: Guida Completa all'Elaborazione Asincrona

Impara a usare Jobs e Queues in Laravel per migliorare le performance e l'esperienza utente.

19 Nov 2025 3 min
Leggi di più →
Laravel

Laravel Testing: TDD con Pest PHP

Impara il Test-Driven Development con Pest, il framework di testing moderno per PHP.

27 Nov 2025 1 min
Leggi di più →

Rimani Aggiornato

Iscriviti alla nostra newsletter per ricevere gli ultimi articoli e novità direttamente nella tua casella di posta.