---
title: "Comprendre l’Argument Resolver de Symfony : Injection Magique ou Logique ?"
date: 2026-01-30T10:29:28.000Z
canonical: https://www.ekino.fr/publications/comprendre-largument-resolver-de-symfony-injection-magique-ou-logique/
---

Vous pensez que l’argument resolving est magique ? En réalité, sa logique est bien plus simple qu’il n’y paraît.

![Image générée avec l’intelligence artificielle](https://www.ekino.fr/media/original/0000/00/e7301e61-1995-9d68-59ae-df513076213c.png)
*Image générée avec l’intelligence artificielle*

#### Qu’est-ce que l’argument resolving ?

L’argument resolving, c’est le moment où Symfony résout les arguments des méthodes d’un contrôleur. Entre autres, c’est le mécanisme qui injecte le fameux objet [Request](https://github.com/symfony/http-foundation/blob/7.3/Request.php) dans la méthode de notre contrôleur, ou encore la variable ***$id*** provenant de l’URL ***path/{id}***.

Je vous ai dit que vous l’utilisez quotidiennement…

#### Un peu d’histoire pour continuer.

L’argument resolving a été introduit dans [Symfony 2](https://symfony.com/doc/2.x/index.html). À l’époque, la résolution des différents arguments était assurée par le [ControllerResolver](https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php). La fonctionnalité, dans sa première version, était un peu rigide : il n’était pas possible de configurer des resolvers personnalisés, et seuls certains types d’arguments pouvaient être résolus, comme l’objet [Request](https://github.com/symfony/http-foundation/blob/7.2/Request.php) ou un attribut de la requête, comme mentionné précédemment.

Dans la version [3.x](https://symfony.com/doc/3.x/index.html) de Symfony, c’est à cette version qu’a été introduite la conception de l’argument resolving que l’on connaît aujourd’hui. La fonctionnalité est devenue extensible, donc la possibilité de créer des resolvers personnalisés est devenue possible.

C’est à partir de cette version-là qu’ont été introduits des resolvers built-in, comme [RequestAttributeValueResolver](https://github.com/symfony/symfony/blob/3.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php), qui est chargé de résoudre les arguments qui seront peuplés par les attributs de la requête, ou encore [ServiceValueResolver](https://github.com/symfony/symfony/blob/3.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/ServiceValueResolver.php), qui permet d’injecter directement tout type de service présent dans le conteneur de services de notre application. Vous pouvez consulter [ici](https://symfony.com/doc/3.x/controller/argument_value_resolver.html#built-in-value-resolvers.) la liste complète des built-in resolvers.

Maintenant qu’on comprend ce qu’est l’argument resolving, voyons voir comment cela fonctionne sous le capot.

#### Comment l’argument resolving est déclenché ?

Tout commence dans [HttpKernel::handleRaw()](https://github.com/symfony/http-kernel/blob/7.3/HttpKernel.php#L155). Symfony cherche à identifier le contrôleur à appeler. Une fois trouvé, c’est l’[ArgumentResolver](https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php) qui prend le relais. Il identifie les arguments de la méthode du contrôleur via l’[API de réflexion](https://www.php.net/manual/en/reflectionclass.getattributes.php), puis il itère dessus pour les résoudre un par un.

#### **Mais comment l’ArgumentResolver sait quel resolver appeler et à quel moment ?**

La réponse à cette question est simple. Tous les resolvers doivent implémenter l’interface [ValueResolverInterface](https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/HttpKernel/Controller/ValueResolverInterface.php). Ces services sont ensuite tagués avec le tag ***controller.argument\_value\_resolver***. Ils forment alors un pool de resolvers qui est injecté dans le service [ArgumentResolver](https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php).

Au moment où l’[ArgumentResolver](https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php) itère sur les arguments des différentes méthodes des contrôleurs, il parcourt également le pool de resolvers. Pour chaque argument, il essaie d’identifier s’il existe un resolver capable de le prendre en charge (c’est-à-dire un resolver qui le "supporte"). Si c’est le cas, le resolver traite l’argument. Dans le cas contraire, une exception est levée pour indiquer que l’argument de la méthode du contrôleur n’a pas pu être résolu.

#### Mais c**omment fonctionne un resolver ?**

Pour vous montrer la résolution d’un argument, je vais prendre l’exemple du [RequestValueResolver](https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestValueResolver.php). J’ai volontairement simplifié la logique du resolver afin que l’idée derrière soit plus facile à comprendre.

Voici le code du resolver, suivi d’une petite explication :

```
namespace SymfonyComponentHttpKernelControllerArgumentResolver;

use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpKernelControllerValueResolverInterface;
use SymfonyComponentHttpKernelControllerMetadataArgumentMetadata;

final class RequestValueResolver implements ValueResolverInterface
{
    public function resolve(Request $request, ArgumentMetadata $argument): array
    {
        if (Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class)) {
            return [$request];
        }

        return [];
    }
}
```

L’[ArgumentResolver](https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php) est en train d’itérer sur une liste d’arguments à résoudre. Notre [RequestValueResolver](https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestValueResolver.php) fait partie du pool de resolvers qui seront appelés, et deux scénarios sont possibles dans notre cas :

***Scénario 1*** : Le type de l’argument de notre itération courant est [Request](https://github.com/symfony/http-foundation/blob/7.3/Request.php). Dans ce cas, on retourne l’objet [Request](https://github.com/symfony/http-foundation/blob/7.3/Request.php), et on passe à l’itération suivante.

***Scénario 2 ***: Le resolver n’est pas capable de résoudre l’argument de l’itération courante. Il retourne alors un tableau vide, ce qui indique à l’[ArgumentResolver](https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php) de passer au resolver suivant pour ce même argument.

En ce qui concerne la dernière étape, la liste des arguments résolus par l’[ArgumentResolver](https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php) est retournée, et le contrôleur est ensuite appelé avec ces arguments.

Pour finir, voici un aperçu d’ensemble. Il s’agit également d’un code simplifié, conçu pour illustrer la vue d’ensemble du mécanisme.

```

// Identification du contrôleur en fonction de la requête courante
if (false === $controller = $this->resolver->getController($request)) {
    throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". The route is wrongly configured.', $request->getPathInfo()));
}

// Dispatch de l’événement kernel.controller
$event = new ControllerEvent($this, $controller, $request, $type);
$this->dispatcher->dispatch($event, KernelEvents::CONTROLLER);
$controller = $event->getController();

// Déclenchement de la résolution des arguments de la méthode du contrôleur
$arguments = $this->argumentResolver->getArguments($request, $controller, $event->getControllerReflector());

// Dispatch de l'événement kernel.controller_arguments
$event = new ControllerArgumentsEvent($this, $event, $arguments, $request, $type);
$this->dispatcher->dispatch($event, KernelEvents::CONTROLLER_ARGUMENTS);
$controller = $event->getController();
$arguments = $event->getArguments();

// Appel du contrôleur
$response = $controller(...$arguments);
```

Le code est un extrait de la méthode [HttpKernel::handleRaw()](https://github.com/symfony/http-kernel/blob/7.3/HttpKernel.php#L155) .

Et voilà, comme vous pouvez le voir, il s’agit d’une fonctionnalité à la fois puissante, scalable et facilement personnalisable, qui permet d’injecter les arguments dans une action de contrôleur sans contrainte d’ordre, et qui améliore la maintenabilité, favorise la séparation des responsabilités et rend les contrôleurs plus propres.

Avant de créer un nouveau resolver, il est recommandé de consulter la liste des [resolvers *built-in*](https://symfony.com/doc/current/controller/value_resolver.html#built-in-value-resolvers), car celui dont vous avez besoin existe peut-être déjà.

J’espère que ce mécanisme vous semble désormais plus clair et que son fonctionnement n’a plus rien de magique.

Si cet article vous a été utile, abonnez-vous au [Medium d’ekino](https://medium.com/@ekino-france) pour découvrir régulièrement des décryptages techniques, retours d’expérience et bonnes pratiques autour du développement.

---

[Comprendre l’Argument Resolver de Symfony : Injection Magique ou Logique ?](https://medium.com/ekino-france/comprendre-largument-resolver-de-symfony-injection-magique-ou-logique-0434d6cbe70e) was originally published in [ekino-france](https://medium.com/ekino-france) on Medium, where people are continuing the conversation by highlighting and responding to this story.
