PHP Framework

Symfony

Symfony est à la fois un ensemble de composants PHP réutilisables et un framework complet construit à partir de ceux-ci. Il privilégie la structure, la stabilité et la maintenabilité à long terme à grande échelle plutôt que la simplicité immédiate.

advanced15 min readUpdated 16 sept. 2026
src/Controller/BlogController.php
php
<?php
// src/Controller/BlogController.php

namespace App\Controller;

use App\Repository\PostRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class BlogController extends AbstractController
{
    #[Route('/blog/{slug}', name: 'blog_show')]
    public function show(string $slug, PostRepository $posts): Response
    {
        $post = $posts->findOneBy(['slug' => $slug]);

        if (!$post) {
            throw $this->createNotFoundException('Post not found');
        }

        return $this->render('blog/show.html.twig', [
            'post' => $post,
        ]);
    }
}
Sortie
2005
Créateur
Fabien Potencier
Langage
PHP
Architecture
Composants plus framework complet
ORM
Doctrine
CLI
bin/console
Config
YAML, XML ou PHP

Pourquoi c'est important

Pourquoi les entreprises choisissent Symfony

Des composants utilisables partout

HttpFoundation, Routing, Console, Mailer et Serializer sont des bibliothèques indépendantes. Vous pouvez en adopter une sans utiliser le framework, et une grande partie de l'écosystème PHP le fait déjà.

Stabilité et support à long terme

Symfony propose des versions LTS (Long Term Support) avec un cycle de dépréciation documenté, rendant les mises à jour prévisibles plutôt que d'imposer des réécritures.

Flex et recettes

Symfony Flex configure les bundles et génère les fichiers de configuration pour vous, permettant d'ajouter une fonctionnalité via un simple composer require.

Le tableau complet

Composants, bundles, conteneur

Des bibliothèques découplées utilisables partout, des bundles pour packager des fonctionnalités, et un conteneur pour tout orchestrer.

Composants

Réutilisation

Bibliothèques autonomes pour le HTTP, le routage, la console, les emails et la sérialisation, compatibles avec tout projet PHP.

Bundles

Packaging

Les bundles regroupent routes, services, configuration et templates dans une unité distribuable, orchestrée par les recettes Flex.

Conteneur

Liaison

Un conteneur de services compilé construit votre graphe d'objets et gère automatiquement l'autowiring des dépendances du constructeur.

HTML5 en un coup d'oeil

La boîte à outils Symfony

Composants

Bibliothèques autonomes utilisables dans n'importe quel projet PHP, avec ou sans le framework.

Bundles

Fonctionnalités packagées regroupant routes, services, configuration et templates.

Recettes Flex

Plugins Composer qui configurent les bundles et créent automatiquement les fichiers de configuration.

Routage par attributs

Déclarez vos routes directement à côté de l'action du contrôleur avec les attributs PHP 8.

Doctrine

Un ORM de type data-mapper avec entités, repositories et migrations.

Console

bin/console permet de générer du code, d'exécuter des migrations, de vider le cache et de consommer des files d'attente.

Un bref aperçu

Un framework et les composants qui le soutiennent

  1. 2005

    Symfony 1

    Fabien Potencier sort un framework pour ses propres projets, inspiré par Rails et Mojavi.

    05
  2. 2011

    Symfony 2

    Une réécriture complète basée sur des composants découplés que d'autres projets peuvent réutiliser.

    11
  3. 2015

    Symfony 3

    Des dépréciations et une API plus propre préparent l'écosystème pour les futures versions majeures.

    15
  4. 2019

    Symfony 4 et Flex

    Les recettes Flex automatisent l'installation des bundles et rendent les applications nettement plus légères.

    19
  5. 2023

    Symfony 7

    Attributs PHP 8, propriétés typées et standards modernes adoptés dans tout le framework.

    23
  6. Aujourd'hui

    Le moteur de PHP

    Les composants Symfony propulsent Laravel, Drupal, phpBB et des milliers de bibliothèques.

    Aujourd'hui

Le guide complet

Symfony: Tout ce que vous devez savoir

Qu’est-ce que Symfony ?

Symfony est deux choses à la fois. C’est un ensemble de composants PHP réutilisables — HttpFoundation, Routing, Console, Mailer, Serializer et des dizaines d’autres — et c’est un framework web complet assemblé à partir de ces composants. Cette double nature explique presque tout : le framework est stable parce que ses parties sont stables, et ses composants sont utiles même utilisés seuls.

Créé par Fabien Potencier en 2005 et maintenu par SensioLabs, Symfony est devenu le moteur du PHP moderne. Laravel est bâti sur des composants Symfony, Drupal et phpBB en dépendent, et des milliers de bibliothèques les utilisent sans jamais toucher au framework complet.

Symfony est plus exigeant qu’un framework « batteries-included ». En retour, il vous offre un système cohérent, extensible et évolutif sur le long terme.

Composants : le véritable produit

Les composants sont le cœur du projet. Chacun d’entre eux résout un problème unique et ne possède aucune dépendance vis-à-vis du framework.

  • HttpFoundation — classes Request et Response orientées objet.
  • Routing — association d’URLs à des contrôleurs via des attributs, YAML ou PHP.
  • Console — création d’outils en ligne de commande avec arguments et options.
  • Mailer — envoi d’e-mails via des transports et des messages templatés.
  • Serializer — conversion d’objets en JSON, XML et inversement.
  • EventDispatcher — découplage du code grâce aux événements et aux listeners.

Vous pouvez installer n’importe lequel d’entre eux directement :

composer require symfony/http-foundation
use Symfony\Component\HttpFoundation\Request;

$request = Request::createFromGlobals();
$page = $request->query->getInt('page', 1);

C’est cette portabilité qui explique pourquoi les composants Symfony se retrouvent partout, même dans des projets qui n’adopteraient jamais le framework complet.

Le noyau HTTP et les contrôleurs

Dans une application complète, chaque requête passe par le HttpKernel. Celui-ci déclenche un événement, fait correspondre une route, appelle un contrôleur et transforme le Response retourné en sortie. Les contrôleurs étendent AbstractController pour bénéficier d’helpers pratiques.

class BlogController extends AbstractController
{
    #[Route('/blog/{slug}', name: 'blog_show')]
    public function show(string $slug, PostRepository $posts): Response
    {
        $post = $posts->findOneBy(['slug' => $slug]);

        if (!$post) {
            throw $this->createNotFoundException('Post not found');
        }

        return $this->render('blog/show.html.twig', ['post' => $post]);
    }
}

Un contrôleur doit retourner une Response. $this->render() en construit une à partir d’un template Twig, $this->json() retourne du JSON, et $this->redirectToRoute() retourne une redirection. Comme l’objet de réponse est explicite, les tests et le middleware sont simplifiés.

Les templates Twig étendent une mise en page de base et remplissent des blocs, et la sortie est échappée sauf si vous choisissez le contraire :

{# templates/blog/show.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <article>
        <h1>{{ post.title }}</h1>
        <p>{{ post.publishedAt|date('F j, Y') }}</p>
        {{ post.body|raw }}
    </article>
{% endblock %}

Routage par attributs

Les routes sont déclarées à côté de l’action qui les gère en utilisant les attributs de PHP 8.

#[Route('/blog', name: 'blog_index', methods: ['GET'])]
#[Route('/blog/{slug}', name: 'blog_show', methods: ['GET'])]

Le routage peut également être défini dans config/routes.yaml si vous préférez le garder séparé. Les attributs sont la norme dans Symfony moderne car la route et la méthode restent liées. Vous pouvez inspecter les routes enregistrées à tout moment avec :

php bin/console debug:router

Le container de services et l’autowiring

Presque tout dans Symfony est un service, et le container se charge de les construire et de les connecter entre eux. Lorsque l’autowiring est activé, il vous suffit de typer les arguments de votre constructeur.

class PostPublisher
{
    public function __construct(
        private EntityManagerInterface $em,
        private MailerInterface $mailer,
    ) {}
}

config/services.yaml indique au container d’effectuer l’autowiring de vos classes :

services:
    _defaults:
        autowire: true
        autoconfigure: true

    App\:
        resource: '../src/'
        exclude:
            - '../src/Entity/'
            - '../src/Kernel.php'

Si deux implémentations d’une même interface existent, liez explicitement la bonne version. Le container est compilé en PHP pur pour la production, ce qui explique sa rapidité malgré la flexibilité dont vous disposez lors du développement.

Bundles et recettes Flex

Un bundle regroupe des fonctionnalités dans une unité distribuable. Les fonctionnalités tierces — Doctrine, la sécurité, le mailer, les panels d’administration — arrivent sous forme de bundle, et le framework lui-même est composé de bundles cœurs.

L’installation d’un bundle se fait via une seule commande :

composer require symfony/orm-pack

Symfony Flex est le plugin Composer qui rend ce processus agréable. Lorsqu’un package possède une recette, Flex crée les fichiers de configuration, enregistre le bundle, et ajoute souvent des variables d’environnement ou un service docker-compose. C’est pourquoi les applications Symfony modernes utilisent une configuration concise et explicite plutôt que des pages entières de code répétitif.

Doctrine ORM

Doctrine est la couche de persistance par défaut. Les entités sont de simples classes PHP annotées avec des attributs de mapping, et les repositories encapsulent les requêtes.

#[ORM\Entity(repositoryClass: PostRepository::class)]
class Post
{
    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private string $title;

    #[ORM\Column(type: 'text')]
    private string $body;

    #[ORM\Column(type: 'datetime_immutable', nullable: true)]
    private ?\DateTimeImmutable $publishedAt = null;
}

Les requêtes sont généralement exprimées via l’API du repository ou en DQL plutôt qu’avec des chaînes SQL :

$latest = $posts->findBy([], ['publishedAt' => 'DESC'], limit: 10);

Les modifications de schéma sont gérées par Doctrine Migrations, qui compare votre mapping à la base de données et génère des fichiers de migration versionnés que vous pouvez examiner avant de les exécuter.

Configuration et environnements

Symfony sépare la configuration du code et l’applique par environnement. APP_ENV sélectionne l’environnement, et les fichiers sous config/ se superposent les uns aux autres.

  • .env contient les valeurs par défaut locales et les variables d’environnement.
  • config/packages/ configure les bundles pour tous les environnements.
  • config/packages/dev/ et config/packages/prod/ permettent de surcharger la configuration par environnement.
  • config/routes.yaml et config/services.yaml correspondent aux paramètres propres à l’application.

L’environnement dev active le profiler et les outils de débogage, test utilise une base de données distincte, et prod compile tout pour optimiser les performances. Vider le cache après des modifications de configuration fait partie intégrante du flux de travail :

php bin/console cache:clear

Messenger et travail asynchrone

Le composant Messenger permet de sortir certaines tâches du cycle de la requête. Vous envoyez un message à un bus et un handler le traite, soit immédiatement, soit via un worker.

final class UserRegistered
{
    public function __construct(public readonly int $userId) {}
}

#[AsMessageHandler]
final class SendWelcomeEmail
{
    public function __invoke(UserRegistered $message): void
    {
        // send the email here
    }
}

Envoyez-le depuis n’importe où, et consommez la file d’attente dans un processus séparé :

$bus->dispatch(new UserRegistered($user->getId()));
php bin/console messenger:consume async

Les transports peuvent être Doctrine, Redis, AMQP ou un service tiers. Les messages en échec peuvent être retentés ou stockés, ce qui fait du traitement en arrière-plan une fonctionnalité native et robuste.

Tests avec PHPUnit

Symfony est livré avec PHPUnit et une classe de base WebTestCase qui démarre le kernel et effectue de réelles requêtes HTTP.

class BlogControllerTest extends WebTestCase
{
    public function testShowPost(): void
    {
        $client = static::createClient();
        $client->request('GET', '/blog/hello-world');

        $this->assertResponseIsSuccessful();
        $this->assertSelectorTextContains('h1', 'Hello world');
    }
}

Comme les services sont injectés, les tests unitaires peuvent remplacer une dépendance par un stub ou un mock sans modifier le container. Réservez les tests d’intégration pour la couche HTTP et les tests unitaires pour les services qui contiennent les règles métier.

Bonnes pratiques

  • Privilégiez l’injection par constructeur plutôt que de récupérer les services depuis le container.
  • Gardez vos controllers légers ; déplacez la logique métier dans des services.
  • Utilisez des repositories pour vos requêtes et ne laissez pas de SQL dans les controllers.
  • Déclarez vos routes via des attributs juste à côté de l’action qu’elles appellent.
  • Laissez Flex gérer la configuration du bundle pour éviter d’écrire du boilerplate.
  • Séparez la configuration par environnement et conservez vos secrets dans des variables d’environnement.
  • Déléguez les tâches lourdes à Messenger plutôt que de les traiter durant la requête.
  • Consultez le profiler lorsque vous constatez des lenteurs ou des comportements inattendus.

Erreurs courantes

  • Appeler $container->get() au lieu d’injecter les dépendances.
  • Placer la logique métier dans les contrôleurs et les entités.
  • Oublier d’enregistrer ou de lier une interface, puis s’interroger sur ce que le container a résolu.
  • Committer des secrets .env au lieu de les exclure du contrôle de version.
  • Modifier des migrations générées après leur exécution.
  • Mélanger aléatoirement les styles de configuration entre YAML, XML et PHP.
  • Ignorer les avis de dépréciation jusqu’à la prochaine mise à jour majeure.

Et après ?

Symfony vous apporte les composants et la rigueur nécessaires pour bâtir des systèmes pérennes, et ses concepts se retrouvent dans de nombreux frameworks de l’écosystème. Consultez le guide Laravel pour voir comment ces composants sont utilisés pour le développement rapide d’applications, ou comparez cette philosophie avec l’approche minimaliste d’Express. Pour concevoir et faire évoluer vos API, poursuivez avec les sections sur le REST et le versionnage d’API.

Récupération d'un service

Laissez le conteneur injecter ce dont vous avez besoin. Extraire manuellement des services du conteneur masque les dépendances et rend la classe plus difficile à tester.

Préférer
class NewsletterService
{
    public function __construct(
        private MailerInterface $mailer,
    ) {}
}
Éviter
class NewsletterService
{
    public function send(): void
    {
        $mailer = $this->container->get('mailer');
        $mailer->send(/* ... */);
    }
}

Recherche d'une entité

Les repositories expriment l'intention et retournent des objets. Le SQL brut dans un contrôleur couple la couche HTTP au schéma et contourne le mapping de Doctrine.

Préférer
$post = $posts->findOneBy(['slug' => $slug]);
if (!$post) {
    throw $this->createNotFoundException();
}
Éviter
$conn = $this->getDoctrine()->getConnection();
$post = $conn->fetchAssociative(
    'SELECT * FROM posts WHERE slug = ?',
    [$slug],
);

Compromis

Symfony est-il le bon framework PHP ?

Symfony sacrifie la gratification instantanée au profit de la structure, de la stabilité et de la réutilisation. Ce choix est payant pour les systèmes complexes et pérennes.

Strengths

  • Composants réutilisables

    Le framework étant assemblé à partir de bibliothèques, vous pouvez intégrer les parties nécessaires dans n'importe quel projet, et vous les retrouvez lorsque vous travaillez sur Drupal ou Laravel.

  • Stabilité et mises à jour prévisibles

    Les versions LTS, les dépréciations documentées et une politique stricte de rétrocompatibilité font des mises à jour un travail planifié plutôt qu'une réécriture.

  • Conçu pour les domaines complexes

    Le conteneur, l'event dispatcher, Messenger, Workflow et les composants de formulaires gèrent le type d'applications qui deviennent trop vastes pour une stack plus simple.

Trade-offs

  • Plus de concepts au départ

    Kernel, conteneur, bundles, environnements et recettes représentent beaucoup d'apprentissage avant d'écrire une fonctionnalité. Prévoyez du temps pour assimiler le modèle mental.

  • Configuration dense

    Même avec Flex, Symfony demande de configurer explicitement les services, le routage et les packages, ce qui est puissant mais verbeux.

  • Prototypage plus lent

    Pour une petite application CRUD, un framework "batteries-included" permet d'obtenir un écran fonctionnel plus rapidement. La structure de Symfony devient avantageuse à mesure que le domaine s'étend.

FAQ

Foire aux questions

Keep learning

Related topics from the roadmap.

$ commencer à apprendre

Prêt à apprendre Symfony ?

Notre tutoriel interactif vous guide à travers Symfony pas à pas — avec des quiz et du vrai code que vous pouvez exécuter dans le navigateur.