← Symfony 8.0 — architecture et préparation certification

Module 2 / 8 · 90 min

Conteneur, configuration et environnement

Rendre les dépendances explicites et distinguer valeurs de configuration.

Votre progression apparaîtra ici lorsque JavaScript est actif.

La progression et le meilleur score sont enregistrés uniquement dans ce navigateur. Aucun compte n’est nécessaire ; effacer les données du navigateur les supprime. Les durées de modules sont indicatives et incluent les exercices.

Comprendre le mécanisme

Le conteneur construit et relie les services. L’autowiring utilise les types ; s’il existe plusieurs implémentations possibles, un alias ou une configuration explicite lève l’ambiguïté. Une décoration enveloppe un service pour étendre son comportement, alors qu’un tag le rend repérable par un mécanisme de collection ou compilation. Les paramètres scalaires et les variables d’environnement demandent un nom et un traitement adaptés.

Raisonner et vérifier

Une variable réellement définie dans l’environnement peut prendre le dessus sur les fichiers dotenv. Les fichiers spécifiques à l’environnement et leurs variantes locales ont un ordre de chargement défini ; inspectez l’origine effective sans afficher les secrets. Utilisez les commandes de diagnostic du conteneur et de configuration pour vérifier vos hypothèses. Un service doit demander ses dépendances utiles plutôt que recevoir tout le conteneur.

Assembler un graphe explicite

Le conteneur organise des services et leurs dépendances selon sa configuration. L’autowiring facilite la résolution de contrats de types, mais ne choisit pas automatiquement toutes les politiques métier. Dessinez le graphe utile au consommateur et donnez des responsabilités ciblées à ses collaborateurs. Une classe facilement instanciable avec des doubles de test expose généralement mieux ses besoins qu’un accès global à des dépendances cachées.

Erreur fréquente à comprendre

Autowiring crée automatiquement toute politique métier.

L’injection ne décide pas les permissions et invariants.

Résoudre une interface sans ambiguïté

Si plusieurs services implémentent une interface injectée, un alias approprié peut désigner explicitement l’implémentation attendue. Le nom du contrat ne suffit pas à déduire ce choix universel. Documentez notamment la différence entre fournisseur réel et laboratoire. Un test doit vérifier la résolution effective du conteneur, sans confondre ce choix technique avec le droit d’un utilisateur à déclencher l’opération correspondante.

Erreur fréquente à comprendre

Toute interface choisit toujours une implémentation unique sans configuration.

Plusieurs services peuvent satisfaire le même type.

Paramètres, valeurs et objets de service

Un paramètre peut représenter une valeur de configuration alors qu’un service possède un comportement et un cycle de vie. Ne supposez pas que tout élément du conteneur est un objet partagé. Définissez type, provenance et sens de la valeur attendue. Une chaîne lue depuis l’environnement peut être absente ou incorrecte ; la commodité de l’injection ne retire pas le besoin de valider le contrat utile.

Erreur fréquente à comprendre

Un paramètre est nécessairement un objet injecté partagé.

La configuration peut porter des valeurs et références différentes.

Environnements et surcharges de configuration

La configuration de test, de développement et de production peut différer. Un service correctement résolu dans un environnement ne prouve pas la même valeur ou le même transport dans l’autre. Reliez les surcharges au scénario voulu et vérifiez l’état effectif. Les diagnostics doivent montrer la configuration publique pertinente sans recopier les secrets ; afficher toutes les variables n’est pas une procédure de résolution acceptable.

Erreur fréquente à comprendre

La configuration test prouve nécessairement toute valeur prod.

Les surcharges et variables peuvent différer.

Durée de vie et état partagé

Un service partagé peut conserver un état entre plusieurs usages selon son environnement d’exécution. Il n’est pas automatiquement isolé par utilisateur. Évitez d’y mémoriser librement un tenant ou un contexte de requête. Si un état est nécessaire, attribuez-lui une portée et une procédure de remise à zéro adaptées. Les tests successifs avec deux identités peuvent révéler une fuite que le seul scénario nominal ne montre pas.

Erreur fréquente à comprendre

Shared signifie isolé automatiquement par utilisateur.

La même instance peut servir plusieurs usages selon son cycle.

Injection ciblée et décoration

Le constructeur rend visibles les contrats nécessaires à un service métier. Une décoration peut ensuite envelopper un comportement existant, par exemple ajouter une mesure autour d’un transport tout en conservant son contrat utile. Elle ne doit pas introduire des effets inattendus ou contourner les permissions. Testez le résultat observable du décorateur et les appels au collaborateur enveloppé, plutôt que supposer que l’assemblage garantit la sémantique.

Erreur fréquente à comprendre

Un accès global au conteneur rend toujours le contrat plus précis.

Il peut masquer les besoins réels de la classe.

Limiter la distribution des secrets

Un credential doit être accessible aux composants qui en ont besoin, avec un périmètre d’environnement et de finalité défini. Le placer dans une variable d’environnement ne rend pas son affichage public inoffensif. Vérifiez les logs, erreurs et artefacts qui peuvent conserver cette valeur. Une correction de visibilité future doit accompagner le retrait d’une capacité réellement compromise si elle a déjà été diffusée.

Erreur fréquente à comprendre

Une variable d’environnement est automatiquement sûre à afficher.

Son mode d’injection ne retire pas sa sensibilité.

Compiler le bon conteneur pour la release

Le cache de conteneur reflète un code et une configuration. Réutiliser aveuglément une ancienne compilation peut conserver des définitions qui ne correspondent plus au déploiement. La préparation de release doit suivre le cycle prévu par le framework et l’environnement réel. Un fichier copié avec succès ne démontre pas que tous les processus ont chargé les services et paramètres attendus.

Erreur fréquente à comprendre

Un cache d’une ancienne configuration reste toujours correct.

Les métadonnées compilées doivent suivre le code et l’environnement.

Versions, tags et traitements de compilation

Les possibilités d’une extension dépendent de la version ciblée et de ses contrats. Les tags peuvent identifier une famille de services pour un traitement de compilation ou un mécanisme prévu par le composant. Le tag seul ne prouve pas que le comportement métier est correct. Vérifiez qui le consomme, quelles données il attend et comment les services concernés sont assemblés dans le conteneur final.

Erreur fréquente à comprendre

Tout exemple de n’importe quelle version est interchangeable.

Les API et options peuvent évoluer.

Tester une résolution réellement utile

Un nom de service présent n’est qu’un début de preuve. Le parcours doit recevoir la bonne implémentation, les bons paramètres et les dépendances nécessaires au comportement attendu. Ajoutez un test de configuration ciblé puis des tests métier qui utilisent les contrats injectés. Une résolution qui n’instancie jamais la classe défectueuse peut laisser une erreur invisible jusqu’au premier appel réel.

Erreur fréquente à comprendre

Un nom de service présent prouve toutes ses valeurs réelles.

La définition doit être compatible et correctement configurée.

Atelier guidé : lire, expliquer et vérifier le code

services:
  App\Billing\Gateway: '@App\Billing\SandboxGateway'
  App\Billing\SandboxGateway: ~
  App\Billing\LiveGateway: ~

L’alias de l’atelier lie Gateway à SandboxGateway dans ce conteneur. LiveGateway existe, mais n’est pas la cible désignée par cet alias. Le choix ne chiffre aucun credential et ne décide pas quels utilisateurs peuvent facturer. Il répond uniquement à la question de l’implémentation assemblée pour ce contrat.

Dans un environnement de laboratoire, obtenez le consommateur qui dépend de Gateway puis vérifiez, par son comportement observable, qu’il utilise le fournisseur sandbox prévu. Configurez ensuite un double de test pour contrôler les données transmises sans appel réseau. Si une décoration est ajoutée, vérifiez qu’elle conserve ce contrat et n’introduit pas une seconde facturation cachée. La preuve doit suivre l’assemblage effectif, pas seulement le nom d’une définition YAML.

Exemple commenté

<?php
interface Notifier { public function send(string $message): void; }
final class ReservationService {
    public function __construct(private readonly Notifier $notifier) {}
    public function accept(): void { $this->notifier->send('accepted'); }
}

Le service dépend d’un contrat fin et peut recevoir un faux notifier en test. Le choix d’une implémentation doit être configuré dans le conteneur.

Exercice de mise en pratique

Ajoutez deux implémentations de Notifier puis résolvez l’ambiguïté sans modifier le service métier.

Voir une proposition de correction

Définissez un alias pour l’interface dans services.yaml. Vérifiez debug:autowiring et remplacez le service dans le conteneur de test. Testez l’envoi sans réseau.

Points de vérification

  • Résoudre les ambiguïtés explicitement.
  • Distinguer tags, alias et décoration.
  • Vérifier la configuration effective sans secrets.

Contrôle de connaissances

Cours associé : Conteneur, configuration et environnement ↗
Deux services implémentent la même interface injectée. Quel mécanisme choisit explicitement celui voulu ?

Documentation de référence ↗

Validation du module

101 questions, objectif pédagogique de 75 %. Durée conseillée de 150 minutes, sans limite imposée. Les questions et les choix sont mélangés ; le corrigé apparaît après validation. Le contrôle rapide de la leçon et l’examen final du cours restent des exercices distincts.

Commencer ou reprendre les 101 questions →