Symfony 8, la nouvelle version majeure du framework PHP
Symfony 8 intègre en profondeur les avancées de PHP 8.4 et supprime toutes les dépréciations de la 7.x, pour de meilleures performances et une expérience développeur améliorée.
Par Pierre Gouedar
Sommaire(15 sections)
- Qu'est-ce que Symfony ?1
- Les nouveautés et améliorations de la version 8 de Symfony2
- Exigence de PHP 8.4 minimum3
- Les commandes invocables (Invokable Commands)4
- Support des enums et DTOs5
- Nouveaux composants stabilisés6
- Nouvelle configuration PHP avec tableaux7
- Gestion améliorée des dates sans fuseau horaire8
- UuidV7 par défaut9
- Améliorations des performances10
- Définition des fonctions et filtres Twig avec attributs11
- Nouvelles contraintes de validation12
- Récapitulatif des différences entre Symfony 8 et 7.413
- Quelle version choisir ?14
- Conclusion15
Qu'est-ce que Symfony ?
Symfony est un framework PHP open-source destiné au développement web moderne. Il permet de créer des applications web performantes grâce à un ensemble de composants réutilisables et une architecture MVC modulaire. Symfony est reconnu pour sa robustesse, sa flexibilité et son écosystème riche comprenant des centaines de packages et bundles. Il est utilisé aussi bien pour des CMS que pour des architectures de plateformes à grande échelle.
Les nouveautés et améliorations de la version 8 de Symfony
Avec la version 8, Symfony intègre en profondeur les dernières avancées de PHP 8.4 et supprime toutes les dépréciations liées à la version 7.0. Cette mise à jour se concentre sur deux axes majeurs : enrichir l'expérience des développeurs et pousser les performances des applications à un niveau supérieur.
Exigence de PHP 8.4 minimum
La plus grosse nouveauté de Symfony 8 est son exigence de PHP 8.4 minimum pour fonctionner. Ce choix stratégique a été fait pour répondre à plusieurs objectifs :
Sécurité : Symfony veut s'assurer de fonctionner sur des versions de PHP les plus récentes, abandonnant ainsi les anciennes versions qui ne reçoivent plus de correctifs de sécurité.
Performances : Grâce à PHP 8.4, Symfony peut exploiter les dernières fonctionnalités liées aux gains de performance, comme les Lazy Objects qui permettent d'initialiser les services uniquement lorsqu'ils sont réellement utilisés.
<?php
use Symfony\Component\DependencyInjection\Attribute\Lazy;
#[Lazy]
class ExpensiveService
{
private DatabaseConnection $connection;
private ComplexCalculator $calculator;
public function __construct(
DatabaseConnection $connection,
ComplexCalculator $calculator
) {
// Initialisé uniquement quand le service est réellement utilisé
}
}Les commandes invocables (Invokable Commands)
L'une des fonctionnalités les plus attendues de Symfony 8 est la stabilisation des commandes invocables. Introduites dans Symfony 7.3 et enrichies dans la version 7.4, elles permettent de simplifier drastiquement l'écriture des commandes console.
Avant (approche classique)
<?php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand(name: 'app:create-user')]
class CreateUserCommand extends Command
{
protected function configure(): void
{
$this->addArgument('name', InputArgument::REQUIRED);
$this->addOption('activate', null, InputOption::VALUE_NONE);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$activate = $input->getOption('activate');
// ...
return Command::SUCCESS;
}
}Après (approche invocable)
<?php
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\Option;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'app:create-user')]
class CreateUserCommand
{
public function __invoke(
SymfonyStyle $io,
#[Argument] string $name,
#[Option] bool $activate = false,
): int {
// $name et $activate sont directement disponibles
return Command::SUCCESS;
}
}Les principaux avantages sont :
- Plus besoin d'hériter de la classe
Command - Plus besoin de surcharger la méthode
configure() - Les valeurs des arguments et options sont directement disponibles comme variables
Support des enums et DTOs
Symfony 8 améliore encore cette fonctionnalité avec le support des backed enums et l'attribut #[MapInput] pour les DTOs :
<?php
enum CloudRegion: string
{
case East = 'east';
case West = 'west';
}
class AddServerInput
{
#[Argument]
public CloudRegion $region;
#[Option]
public ?int $size = null;
}
#[AsCommand('app:add-server')]
class AddServerCommand
{
public function __invoke(
OutputInterface $output,
#[MapInput] AddServerInput $server,
): int {
// Utilisation de $server->region et $server->size
return Command::SUCCESS;
}
}Nouveaux composants stabilisés
Symfony 8 améliore plusieurs composants qui étaient expérimentaux dans la version 7.x :
TypeInfo
Le composant TypeInfo extrait les informations de type PHP depuis les propriétés, arguments et types de retour. Il gère les unions, intersections et génériques.
<?php
use Symfony\Component\TypeInfo\TypeResolver\TypeResolver;
class Dummy
{
public function __construct(
public int $id,
/** @var string[] $tags */
public array $tags,
) {
}
}
$typeResolver = TypeResolver::create();
$typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id'));
// Retourne un type "int"ObjectMapper
Le composant ObjectMapper simplifie la transformation d'objets, particulièrement utile pour mapper des DTOs vers des entités. Dans l'exemple ci-dessous, on définit un ProductInputDto qui sera automatiquement converti en entité Product grâce aux attributs #[Map] :
<?php
use App\Entity\Product;
use Symfony\Component\ObjectMapper\Attribute\Map;
#[Map(target: Product::class)]
class ProductInputDto
{
#[Map(target: 'name')]
public string $productName;
public string $description;
#[Map(if: false)]
public string $internalSku = '';
#[Map(transform: 'floatval')]
public string $price;
}Utilisation dans un contrôleur :
<?php
#[Route('/product', name: 'product_create', methods: ['POST'])]
public function create(
#[MapRequestPayload] ProductInputDto $productInput,
ObjectMapperInterface $objectMapper,
EntityManagerInterface $entityManager
): Response {
$product = $objectMapper->map($productInput);
$entityManager->persist($product);
$entityManager->flush();
return $this->json(['message' => 'Produit créé']);
}JsonPath
Le composant JsonPath permet d'interroger et d'extraire des données JSON en utilisant des expressions, similaire à DomCrawler pour le HTML :
<?php
use Symfony\Component\JsonPath\JsonCrawler;
$json = '{"store": {"books": [{"title": "Symfony Guide", "price": 29.99}]}}';
$crawler = new JsonCrawler($json);
$titles = $crawler->find('$.store.books[*].title');
// Filtre avancé
$cheapBooks = $crawler->find('$.store.books[?(@.price < 30)]');JsonStreamer
Pour les APIs manipulant de gros volumes JSON, JsonStreamer offre un encodeur/décodeur streaming environ 10× plus rapide et 50-90% plus léger en mémoire que le Serializer :
<?php
use Symfony\Component\JsonStreamer\JsonStreamEncoder;
$encoder = new JsonStreamEncoder();
foreach ($encoder->encode($largeDataset) as $chunk) {
echo $chunk;
}Nouvelle configuration PHP avec tableaux
Symfony 8 abandonne les configurations XML et PHP fluent au profit des tableaux PHP. Un format compact et expressif avec autocomplétion et validation de types :
<?php
// config/packages/security.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
return App::config([
'security' => [
'firewalls' => [
'main' => [
'pattern' => '^/*',
'lazy' => true,
'anonymous' => true,
],
],
'access_control' => [
['path' => '^/admin', 'roles' => 'ROLE_ADMIN'],
],
]
]);Pour ceux qui ne sont pas prêts, YAML reste disponible.
Gestion améliorée des dates sans fuseau horaire
Symfony 8 introduit un nouveau système pour gérer les dates "flottantes", ces dates qui n'ont pas de fuseau horaire associé, comme une date de naissance ou une alarme quotidienne.
Le problème
PHP associait automatiquement un fuseau horaire à toutes les dates, ce qui créait des décalages inattendus. Une date de naissance comme "15 mai 1990" pouvait se transformer en "14 mai 1990 à 23h" selon le fuseau du serveur.
La solution
Symfony propose désormais trois types de points temporels :
<?php
use Symfony\Component\Form\Extension\Core\Type\DateType;
// Pour une date (ex : 2025-10-29)
$builder->add('birthdate', DateType::class, [
'input' => 'date_point', // Utilise DayPoint
]);
// Pour une heure
$builder->add('alarm', TimeType::class, [
'input' => 'date_point', // Utilise TimePoint
]);UuidV7 par défaut
Symfony 8 utilise maintenant UuidV7 par défaut pour les identifiants uniques. Cette version est plus précise, capable de gérer le temps à la microseconde tout en respectant la RFC 9562.
Pour les tests, un nouvel outil MockUuidFactory permet de fixer les UUID générés :
<?php
use Symfony\Component\Uid\Factory\MockUuidFactory;
$factory = new MockUuidFactory('01912d08-2000-7000-8000-000000000001');
// Tous les UUID générés seront prévisibles pendant les testsAméliorations des performances
Symfony 8 apporte des optimisations significatives :
- Lazy Objects PHP 8.4 : Les services sont initialisés uniquement à l'utilisation
- Compilation du conteneur optimisée : Plus de dépendances résolues au moment du build
- Cache Twig amélioré : Chargement plus fluide des templates
- Gestion des routes accélérée : Résolution plus rapide
- Support natif de FrankenPHP : Un serveur PHP haute performance basé sur Go et Caddy
# docker-compose.yml avec FrankenPHP
services:
app:
image: dunglas/frankenphp:latest
environment:
FRANKENPHP_CONFIG: "worker ./bin/frankenphp-worker.php"Définition des fonctions et filtres Twig avec attributs
Plus besoin d'étendre une classe de base pour créer des extensions Twig. Les fonctions et filtres sont désormais définis avec des attributs et chargés en lazy-loading :
<?php
use Twig\Attribute\AsTwigFilter;
use Twig\Attribute\AsTwigFunction;
class AppExtension
{
#[AsTwigFilter('product_number')]
public function formatProductNumber(string $number): string
{
return 'PRD-' . strtoupper($number);
}
#[AsTwigFunction('current_user')]
public function getCurrentUser(): ?User
{
// ...
}
}Nouvelles contraintes de validation
Symfony 8 enrichit son système de validation avec de nouvelles contraintes intégrées :
- Validation de charsets
- Validation d'adresses MAC
- Validation de numéros de semaine ISO
- Comptage de mots
- Validation de syntaxe YAML
- Validation de slugs
- Validation de syntaxe Twig
- Validation de fichiers vidéo
Récapitulatif des différences entre Symfony 8 et 7.4
| Fonctionnalité | Symfony 7.4 | Symfony 8.0 |
|---|---|---|
| Version PHP minimum | PHP 8.2 | PHP 8.4 |
| Dépréciations | Contient toutes les dépréciations 7.x | Aucune dépréciation |
| Support | LTS (bugs: Nov 2028, sécurité: Nov 2029) | Regular (bugs et sécurité: Juil 2026) |
| Commandes invocables | Disponibles | Stabilisées et améliorées |
| TypeInfo, ObjectMapper, JsonPath | Expérimentaux | Stabilisés |
| Configuration | XML, YAML, PHP fluent | Tableaux PHP (+ YAML) |
| Lazy Objects | Non disponible | Support natif PHP 8.4 |
| UuidV7 | Optionnel | Par défaut |
| Code source | Inclut les couches de dépréciation | 13 202 lignes supprimées |
Quelle version choisir ?
Symfony 7.4 LTS est recommandé si :
- Vous avez besoin d'un support long terme (4 ans de bugs, 5 ans de sécurité)
- Vous ne pouvez pas migrer immédiatement vers PHP 8.4
- Vous utilisez des bundles qui n'ont pas encore été mis à jour
Symfony 8.0 est recommandé si :
- Vous pouvez utiliser PHP 8.4
- Vous souhaitez bénéficier des dernières fonctionnalités
- Vous préférez corriger les dépréciations progressivement entre versions mineures
- Vous êtes un early adopter ou une startup avec une forte pression d'innovation
La recommandation officielle de Symfony est d'utiliser les versions régulières chaque fois que possible.
Conclusion
Pour ses 20 ans, Symfony 8 est une version qui marque le coup. Ce n'est pas juste une série de petites améliorations mais d'innovations majeures. Entre les commandes invocables qui transforment notre manière de coder, et l'intégration de composants comme ObjectMapper et JsonPath, cette nouvelle version va permettre aux développeur un gain de temps. Sans oublier les performances améliorées grâce à l'optimisation pour PHP 8.4. Un autre atout de Symfony 8 est l'adoption des attributs PHP natifs qui permet de dire adieu au boilerplate. Le code est devenu plus propre, plus lisible, et sa maintenance est un jeu d'enfant. En clair, pour quiconque veut bâtir des applications PHP modernes et solides, maîtriser Symfony 8 n'est plus une option, il s'agit de la marche à suivre.
Ressources et Documentation
- Documentation officielle de Symfony : https://symfony.com/doc/current/index.html
- Guide de migration vers Symfony 8 : https://symfony.com/doc/current/setup/upgrade_major.html
- Releases Symfony : https://symfony.com/releases
- Notes de version PHP 8.4 : https://www.php.net/releases/8.4/
Pierre Gouedar
