> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Conteneur de services

> Fonctionnement de l'injection de dépendances via le conteneur de services de Laravel et bases des bindings.

## Qu'est-ce que le conteneur de services

Le conteneur de services de Laravel est le mécanisme qui gère les dépendances des classes et effectue l'injection de dépendances. Injecter une dépendance, c'est fournir à une classe ce dont elle a besoin via son constructeur (ou parfois via un setter).

Voyons l'exemple suivant.

```php theme={null}
<?php

namespace App\Http\Controllers;

use App\Services\AppleMusic;
use Illuminate\View\View;

class PodcastController extends Controller
{
    /**
     * Crée une nouvelle instance de contrôleur.
     */
    public function __construct(
        protected AppleMusic $apple,
    ) {}

    /**
     * Affiche les informations du podcast.
     */
    public function show(string $id): View
    {
        return view('podcasts.show', [
            'podcast' => $this->apple->findPodcast($id)
        ]);
    }
}
```

Ici, `PodcastController` a besoin d'aller chercher un podcast depuis Apple Music. On **injecte** donc un service capable de le faire. Cette injection permet aussi de remplacer facilement `AppleMusic` par un mock lors des tests.

<Info>
  Une bonne compréhension du conteneur de services est essentielle pour construire des applications Laravel de grande taille. C'est également utile si vous contribuez au cœur de Laravel.
</Info>

```mermaid theme={null}
flowchart TD
    A["Service provider<br>register()"] --> B["Conteneur de services<br>Enregistrement du binding"]
    B --> C{"Résolution<br>make() / injection automatique"}
    C -- "Classe concrète" --> D["Résolution automatique<br>par réflexion"]
    C -- "Interface" --> E["Résolution vers<br>l'implémentation enregistrée"]
    D --> F["Création de l'instance<br>Injection dans le constructeur"]
    E --> F
```

## Résolution sans configuration

Si une classe ne dépend que d'autres classes concrètes (pas d'interfaces), aucune configuration n'est nécessaire. Par exemple, dans `routes/web.php` :

```php theme={null}
<?php

class Service
{
    // ...
}

Route::get('/', function (Service $service) {
    dd($service::class);
});
```

<Info>
  Cet exemple définit une classe dans le fichier de routes uniquement à des fins de démonstration. En pratique, placez vos services dans `app/Services`.
</Info>

En accédant à cette route, Laravel résout automatiquement `Service` et l'injecte dans le handler. Aucune configuration nécessaire.

De nombreuses classes Laravel (contrôleurs, listeners, middlewares) reçoivent leurs dépendances automatiquement via le conteneur.

## Bindings

### Bindings de base

La plupart des bindings s'enregistrent dans un [service provider](/fr/service-providers). Dans un provider, `$this->app` donne accès au conteneur.

#### bind

`bind` associe une classe ou une interface à une closure.

```php theme={null}
use App\Services\Transistor;
use App\Services\PodcastParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->bind(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});
```

La closure reçoit le conteneur en argument, ce qui permet de résoudre des sous-dépendances.

Hors d'un service provider, utilisez la façade `App` pour interagir avec le conteneur.

```php theme={null}
use App\Services\Transistor;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\App;

App::bind(Transistor::class, function (Application $app) {
    // ...
});
```

<Info>
  Les classes qui ne dépendent pas d'interfaces n'ont pas besoin d'être enregistrées. Le conteneur les résout automatiquement via réflexion.
</Info>

#### singleton

`singleton` lie une classe/interface à une résolution unique. La même instance est renvoyée à chaque appel suivant.

```php theme={null}
use App\Services\Transistor;
use App\Services\PodcastParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->singleton(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});
```

#### instance

Vous pouvez également binder une instance existante avec `instance`. Le conteneur renverra toujours cette instance.

```php theme={null}
use App\Services\Transistor;
use App\Services\PodcastParser;

$service = new Transistor(new PodcastParser);

$this->app->instance(Transistor::class, $service);
```

### Binding d'une interface à une implémentation

Une des grandes forces du conteneur : associer une interface à une implémentation. Par exemple, l'interface `EventPusher` et l'implémentation `RedisEventPusher` :

```php theme={null}
use App\Contracts\EventPusher;
use App\Services\RedisEventPusher;

$this->app->bind(EventPusher::class, RedisEventPusher::class);
```

Le conteneur injectera `RedisEventPusher` partout où `EventPusher` est demandé. Il suffit de type-hinter `EventPusher` dans le constructeur.

```php theme={null}
use App\Contracts\EventPusher;

/**
 * Crée une nouvelle instance.
 */
public function __construct(
    protected EventPusher $pusher,
) {}
```

<Tip>
  Dépendre d'une interface permet de changer d'implémentation sans modifier le code appelant. Cela facilite les tests et l'évolution.
</Tip>

## Résolution automatique (DI par type-hint)

Lorsqu'il résout un contrôleur, un listener ou un middleware, le conteneur inspecte les type-hints du constructeur et injecte automatiquement les dépendances.

```php theme={null}
<?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
     * Crée une nouvelle instance de contrôleur.
     */
    public function __construct(
        protected UserRepository $users,
    ) {}
}
```

Si `UserRepository` ne dépend pas d'une interface, aucun enregistrement n'est nécessaire. Un simple accès à la route déclenche l'injection automatique.

## Résolution depuis le conteneur

### Méthode `make`

Résolvez une instance avec `make`.

```php theme={null}
use App\Services\Transistor;

$transistor = app()->make(Transistor::class);
```

Si la classe a des dépendances non résolubles, `makeWith` permet de passer des arguments supplémentaires.

```php theme={null}
$transistor = $this->app->makeWith(Transistor::class, ['id' => 1]);
```

### Injection automatique

En pratique, vous appelez rarement `make` directement. Il suffit d'ajouter les type-hints dans le constructeur d'une classe résolue par Laravel (contrôleurs, listeners, middlewares) pour que l'injection se fasse automatiquement.

## Façades et conteneur

Les façades fournissent une interface statique vers les objets du conteneur. Par exemple, `Cache::get()` récupère en interne le service `Cache` depuis le conteneur.

```php theme={null}
use Illuminate\Support\Facades\Cache;

// Via la façade
Cache::get('key');

// Équivalent via le conteneur
app('cache')->get('key');
```

Les façades sont un wrapper pratique du conteneur. Vous pouvez également substituer la façade par un mock pour les tests.

```php theme={null}
use Illuminate\Support\Facades\Cache;

Cache::shouldReceive('get')
    ->once()
    ->with('key')
    ->andReturn('value');
```

## Exemple d'injection dans le constructeur

Voyons un pattern typique.

<Steps>
  <Step title="Définir l'interface">
    ```php theme={null}
    <?php

    namespace App\Contracts;

    interface PaymentGateway
    {
        public function charge(int $amount, string $token): bool;
    }
    ```
  </Step>

  <Step title="Créer l'implémentation">
    ```php theme={null}
    <?php

    namespace App\Services;

    use App\Contracts\PaymentGateway;

    class StripePaymentGateway implements PaymentGateway
    {
        public function charge(int $amount, string $token): bool
        {
            // Traitement du paiement via l'API Stripe...
            return true;
        }
    }
    ```
  </Step>

  <Step title="Enregistrer le binding dans un service provider">
    ```php theme={null}
    use App\Contracts\PaymentGateway;
    use App\Services\StripePaymentGateway;

    $this->app->singleton(PaymentGateway::class, StripePaymentGateway::class);
    ```
  </Step>

  <Step title="Recevoir l'injection dans le contrôleur">
    ```php theme={null}
    <?php

    namespace App\Http\Controllers;

    use App\Contracts\PaymentGateway;
    use Illuminate\Http\Request;

    class OrderController extends Controller
    {
        public function __construct(
            protected PaymentGateway $payment,
        ) {}

        public function store(Request $request)
        {
            $this->payment->charge(
                $request->amount,
                $request->payment_token
            );

            // ...
        }
    }
    ```
  </Step>
</Steps>

Grâce à ce pattern, changer de fournisseur de paiement (`Stripe` vers un autre) se fait en modifiant un seul binding.

## Prochaines étapes

<Card title="Service providers" icon="plug" href="/fr/service-providers">
  Apprenez à enregistrer des bindings via les service providers.
</Card>


## Related topics

- [Service providers](/fr/service-providers.md)
- [Cycle de vie d'une requête](/fr/lifecycle.md)
- [Implémenter un guard d'authentification personnalisé](/fr/advanced/custom-auth-guard.md)
- [Structure d'application Laravel 11+](/fr/advanced/app-structure.md)
- [Façades](/fr/facades.md)
