Passer au contenu principal
Au démarrage de Laravel, les service providers enregistrés sont chargés à chaque requête, même si leur fonctionnalité n’est jamais utilisée durant celle-ci. Les service providers différés (Deferred Service Provider) résolvent ce problème en retardant le chargement jusqu’à ce que le service soit réellement utilisé.
Cette page suppose la connaissance des bases du développement de packages. Il est recommandé de comprendre le fonctionnement de base des service providers avant de la lire.

Pourquoi les providers différés sont nécessaires

Les service providers ordinaires voient leurs register() et boot() appelés à chaque requête. Initialiser à chaque fois des fonctionnalités que toutes les pages n’utilisent pas — envoi d’e-mails, queues, cache — est un gaspillage.
// Le register() de ce provider est appelé à chaque requête
class ReportServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Lier un service de rapport lourd à chaque fois
        $this->app->singleton(ReportGenerator::class, function ($app) {
            return new ReportGenerator(
                $app->make(PdfRenderer::class),
                $app->make(ChartRenderer::class),
                $app->make(DataExporter::class),
            );
        });
    }
}
Le rendre différé fait que l’initialisation n’a lieu que pour les requêtes qui génèrent réellement un rapport.

L’interface DeferrableProvider

Illuminate\Contracts\Support\DeferrableProvider est une interface simple avec une seule méthode provides().
namespace Illuminate\Contracts\Support;

interface DeferrableProvider
{
    public function provides();
}
Il suffit d’implémenter cette interface pour que le provider passe en mode différé.

Implémentation de base

L’implémentation d’un provider différé se fait en trois étapes.
1

Implémenter DeferrableProvider

use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;

class ReportServiceProvider extends ServiceProvider implements DeferrableProvider
{
    // ...
}
2

Lier les services dans register()

Écrivez les bindings dans register() comme dans un provider ordinaire.
public function register(): void
{
    $this->app->singleton(ReportGenerator::class, function ($app) {
        return new ReportGenerator(
            $app->make(PdfRenderer::class),
            $app->make(ChartRenderer::class),
            $app->make(DataExporter::class),
        );
    });

    $this->app->singleton(ReportRepository::class, function ($app) {
        return new ReportRepository($app->make('db'));
    });
}
3

Retourner les services enregistrés dans provides()

provides() doit retourner tous les services liés dans register(). Laravel se base sur cette liste pour déterminer « quel provider charger lorsque tel service est demandé ».
public function provides(): array
{
    return [
        ReportGenerator::class,
        ReportRepository::class,
    ];
}

Mécanisme du manifeste des services

Au démarrage, Laravel génère un fichier manifeste bootstrap/cache/services.php. Ce fichier contient la liste des services fournis par les providers différés.
// Exemple de bootstrap/cache/services.php (généré automatiquement)
return [
    'providers' => [
        // Même liste que bootstrap/providers.php
    ],
    'eager' => [
        // Providers à chargement immédiat
        App\Providers\AppServiceProvider::class,
    ],
    'deferred' => [
        // Mapping nom de service => classe de provider
        'App\Services\ReportGenerator' => ReportServiceProvider::class,
        'App\Repositories\ReportRepository' => ReportServiceProvider::class,
        'cache'     => Illuminate\Cache\CacheServiceProvider::class,
        'cache.store' => Illuminate\Cache\CacheServiceProvider::class,
        'queue'     => Illuminate\Queue\QueueServiceProvider::class,
    ],
    'when' => [],
];
Grâce à ce manifeste, Laravel sait « quel provider fournit ce service » sans avoir à charger de fichiers. Le provider réel n’est chargé que lorsque le service correspondant est résolu pour la première fois.
Après avoir ajouté ou modifié un provider, régénérez le manifeste.
php artisan optimize:clear
# ou
php artisan clear-compiled

Flux du fonctionnement interne


Importance de la méthode provides()

Si provides() contient un oubli, le service correspondant ne sera jamais résolu.
public function register(): void
{
    $this->app->singleton(ReportGenerator::class, fn ($app) => new ReportGenerator());

    // Binding supplémentaire
    $this->app->singleton('report', fn ($app) => $app->make(ReportGenerator::class));
}

public function provides(): array
{
    return [
        ReportGenerator::class,
        'report',  // ← N'oubliez pas de mentionner aussi les bindings à clé chaîne
    ];
}
Idem lorsque vous utilisez les propriétés $bindings / $singletons : incluez-les dans provides().
class AnalyticsServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public $singletons = [
        AnalyticsClient::class => DefaultAnalyticsClient::class,
    ];

    public function provides(): array
    {
        // Retourner toutes les clés listées dans $singletons
        return [
            AnalyticsClient::class,
        ];
    }
}

Contraintes des providers différés

Les providers différés conviennent aux providers dont le seul objectif est l’enregistrement de bindings dans le conteneur. Les providers qui effectuent les opérations ci-dessous dans boot() ne peuvent pas être différés.
ContrainteRaison
Enregistrement de routesLes routes sont résolues au démarrage de l’app, le différé ne fonctionne pas
Enregistrement de middlewares globauxDoit se faire avant le traitement de la requête
Enregistrement d’event listeners (permanents)Doit être enregistré avant que l’événement soit émis
Ajout de directives BladeDoit être enregistré avant la compilation des vues
Écrire une méthode boot() dans un provider différé est possible, mais son contenu ne s’exécutera que lorsqu’un service sera résolu. Écrire des « traitements toujours nécessaires » comme des routes ou des middlewares dans boot() produit des comportements inattendus.

La méthode when() — enregistrement déclenché par un événement

La méthode when() permet d’enregistrer un provider lorsqu’un événement particulier est émis. Utile pour des providers nécessaires uniquement dans certains contextes (traitement de jobs, etc.).
class ReportServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->app->singleton(ReportGenerator::class, fn () => new ReportGenerator());
    }

    public function provides(): array
    {
        return [ReportGenerator::class];
    }

    /**
     * Charger le provider aussi lorsque les événements spécifiés
     * sont émis, en plus de la résolution d'un binding de service.
     */
    public function when(): array
    {
        return [
            \App\Events\ReportRequested::class,
        ];
    }
}
Lorsque l’un des événements retournés par when() est émis, le provider est chargé même si aucun service n’a été directement résolu.

Utilisation dans le développement de packages

Pour un package tiers, les providers différés contribuent également aux performances de l’application utilisatrice.

Pattern recommandé

namespace Acme\Analytics;

use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;

class AnalyticsServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->mergeConfigFrom(__DIR__.'/../config/analytics.php', 'analytics');

        $this->app->singleton(AnalyticsManager::class, function ($app) {
            return new AnalyticsManager($app->make('config')->get('analytics'));
        });

        $this->app->singleton('analytics', fn ($app) => $app->make(AnalyticsManager::class));
    }

    public function boot(): void
    {
        // Utiliser boot() uniquement pour l'enregistrement des publications
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__.'/../config/analytics.php' => config_path('analytics.php'),
            ], 'analytics-config');
        }
    }

    public function provides(): array
    {
        return [
            AnalyticsManager::class,
            'analytics',
        ];
    }
}
mergeConfigFrom() vérifie en interne si la configuration est en cache, donc l’appeler dans le register() d’un provider différé est sûr. Si la configuration est déjà en cache, cela ne fait rien.

Séparer l’enregistrement des commandes Artisan avec runningInConsole()

L’enregistrement de commandes n’est nécessaire qu’au démarrage d’Artisan ; branchez donc avec runningInConsole(). Toutefois, si vous différez un provider qui fournit des commandes, incluez la classe de commande dans provides() ou séparez les commandes dans un provider dédié.
public function boot(): void
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            AnalyticsFlushCommand::class,
        ]);
    }
}

Exemples d’utilisation dans le cœur de Laravel

Beaucoup des providers du cœur de Laravel sont des providers différés. C’est une conception qui évite de charger immédiatement tous les services non utilisés à chaque requête.
ProviderServices fournis
CacheServiceProvidercache, cache.store, RateLimiter
QueueServiceProviderqueue, queue.worker, queue.failer
MailServiceProvidermail.manager, mailer
RedisServiceProviderredis, redis.connection
HashServiceProviderhash, hash.driver
ValidationServiceProvidervalidator, validation.presence
TranslationServiceProvidertranslator
BroadcastServiceProviderBroadcast
Dans une application composée uniquement d’endpoints API, MailServiceProvider ou BroadcastServiceProvider peuvent ne jamais être chargés durant une requête.

Critères pour décider de différer ou non

  • Services qui ne sont pas utilisés à chaque requête (mail, rapports, clients d’API externes, etc.)
  • Services dont l’initialisation nécessite une connexion externe ou la lecture de fichiers
  • Services avec un graphe d’objets lourd
  • Providers fournissant des commandes utilisées uniquement en CLI
  • Providers qui enregistrent des routes (loadRoutesFrom, etc.)
  • Providers qui enregistrent des middlewares ou gestionnaires d’exceptions actifs en permanence
  • Providers qui enregistrent des global scopes ou observers Eloquent
  • Services légers utilisés dans la majorité des requêtes (le surcoût du différé peut être supérieur)

Pages associées

Bases du développement de packages

Découvrez le développement de packages Laravel, avec les service providers comme noyau.

Gestion de la compatibilité des versions de packages

Stratégies de maintenance de packages pour suivre les montées de version majeures de Laravel et PHP.
Dernière modification le 13 juillet 2026