Retour au blog
Présentation 04/04/2026 13 min de lecture

Spring Boot et Symfony : mon parcours de Java vers PHP et ce que les deux mondes m’ont appris

J’ai commencé par Java avant de basculer vers PHP, que j’ai appris en grande partie par moi-même à l’époque où PHP 4 ne poussait pas encore la programmation objet comme aujourd’hui. Avec le recul, comparer Spring Boot et Symfony permet de mieux comprendre deux visions très solides du développement backend moderne.

Spring Boot et Symfony : mon parcours de Java vers PHP et ce que les deux mondes m’ont appris

J’ai commencé ma vie de développeur avec Java. C’est un langage que j’ai pratiqué pendant mes études et dans mes premières expériences, à une époque où il incarnait pour moi quelque chose de très structuré : typage fort, architecture claire, séparation des responsabilités, culture du code maintenable et logique orientée objet assumée.

Puis, avec le temps, j’ai basculé vers PHP. Et ce qui est amusant, c’est que PHP, je l’ai appris en grande partie par moi-même. À l’époque de PHP 4, on n’était pas du tout dans le même confort qu’aujourd’hui. La programmation objet existait, mais elle n’avait ni la maturité, ni l’élégance, ni la cohérence qu’on connaît aujourd’hui avec PHP moderne, Symfony, Composer, les standards PSR, Doctrine, les tests et tout l’écosystème actuel.

Quand on vient de Java, il y a souvent un réflexe un peu hautain au début vis-à-vis de PHP. Je l’ai vu, je l’ai entendu, et pour être honnête, je l’ai peut-être eu moi aussi au départ. On se dit que Java est plus sérieux, plus propre, plus robuste par nature. Et puis, en avançant, on comprend que ce n’est pas aussi simple. Un langage seul ne fait pas la qualité d’un projet. Ce qui compte, c’est l’écosystème, les outils, les pratiques, le cadre architectural et surtout la manière de coder.

C’est justement pour ça que je trouve la comparaison entre Spring Boot et Symfony intéressante. Pas pour désigner un gagnant. Mais parce qu’en réalité, ces deux mondes ont plus de choses en commun qu’on ne le croit, surtout quand on regarde leur maturité backend et leur façon d’organiser une application web sérieuse.

Pourquoi comparer Spring Boot et Symfony ?

Comparer Spring Boot et Symfony, ce n’est pas comparer deux outils qui jouent dans des catégories totalement différentes. Dans les deux cas, on parle d’environnements capables de structurer une vraie application métier, de gérer le routing, l’injection de dépendances, la configuration, la sécurité, les accès aux données et l’exposition d’API web.

Spring Framework s’appuie historiquement sur l’IoC et la dependency injection comme fondation centrale. Spring Boot est venu ensuite accélérer le démarrage et l’industrialisation des applications. Symfony, de son côté, documente lui aussi un service container, l’autowiring, le routing, les contrôleurs et toute une approche modulaire qui permet de construire des applications très propres. Fabien Potencier a d’ailleurs expliqué publiquement que la couche de dependency injection de Symfony 2.0 avait été inspirée par Spring.

Autrement dit, quand un développeur Java arrive sur Symfony, il n’arrive pas en terrain totalement inconnu. Il retrouve beaucoup d’idées familières : services, conteneur, injection, séparation nette des couches, configuration structurée, architecture lisible et cadre favorable aux bonnes pratiques.

Mon ressenti de développeur passé de Java à PHP

Ce que Java m’a apporté très tôt, c’est la rigueur. Quand on développe avec Spring, on est poussé vers une discipline d’architecture. On pense en couches. On pense services, repositories, DTO, configuration, cycle de vie de l’application. On prend vite l’habitude de construire quelque chose d’ordonné.

PHP, lui, m’a apporté autre chose : la vitesse d’exécution dans le quotidien du développeur, la souplesse, le pragmatisme et une courbe de mise en œuvre parfois plus directe. Quand PHP moderne est bien utilisé, surtout avec Symfony, il permet d’aller très vite tout en gardant un très bon niveau de structure.

Avec le recul, je dirais que Spring Boot donne souvent une sensation de puissance industrielle, là où Symfony donne une sensation d’efficacité très fine. Spring Boot me fait penser à un environnement extrêmement solide, pensé pour des équipes qui aiment standardiser fort. Symfony me fait penser à un framework très élégant, très clair, qui laisse beaucoup de contrôle sans t’abandonner au chaos.

Sur l’architecture, Spring Boot et Symfony se comprennent très bien

Dans Spring, la documentation officielle rappelle que l’injection de dépendances est au cœur du fonctionnement du framework. Les objets définissent leurs dépendances, puis le conteneur les injecte. Symfony décrit la même philosophie avec son service container, qui centralise la création des objets et favorise une architecture forte. Symfony documente aussi l’autowiring comme un mécanisme prédictible basé sur les type-hints.

Pour quelqu’un qui a connu Spring, voir une classe de service Symfony injectée proprement dans un contrôleur ou dans un autre service n’a rien de choquant. Au contraire, cela donne une impression familière. Les noms changent un peu, les conventions aussi, mais le fond architectural est très proche.

La vraie différence : la culture de l’écosystème

La plus grosse différence, à mon avis, n’est pas dans les concepts. Elle est dans la culture de l’écosystème.

Spring Boot vit dans le monde Java. On est dans un univers historiquement très orienté entreprise, fort typage, build Maven ou Gradle, annotations très présentes, outillage mature, culture de standardisation importante. On démarre vite avec Spring Boot, notamment via Spring Initializr, mais on sent tout de suite le poids positif d’un écosystème pensé pour des projets ambitieux, souvent d’équipe.

Symfony vit dans le monde PHP. L’ambiance est différente. Plus pragmatique, parfois plus légère, souvent plus directe. Mais ce qui est intéressant, c’est que Symfony a énormément professionnalisé le développement PHP moderne. Le routing, les contrôleurs, le container, les événements, la configuration et l’intégration avec Doctrine donnent aujourd’hui un cadre très sérieux.

Spring Boot va souvent plus vite au démarrage “stack complète”, Symfony va souvent plus vite dans le raffinement

Je caricature un peu, mais je trouve que Spring Boot est redoutable pour générer une base applicative cohérente très vite avec une stack déjà bien alignée. Entre Spring Web, Spring Data JPA, Spring Security, Actuator et l’écosystème officiel, on obtient rapidement une application très industrialisable.

Symfony, de son côté, me plaît beaucoup pour sa finesse. Son architecture est très lisible, son container est puissant, son système de routing reste très agréable, et l’intégration progressive des briques via Flex ou Composer donne beaucoup de maîtrise. J’ai souvent le sentiment qu’avec Symfony, on garde une vision très nette de ce qu’on installe et de ce qu’on branche.

Doctrine et JPA : cousins dans l’esprit, différents dans l’usage

Quand on compare la persistance, la parenté intellectuelle entre Doctrine ORM côté Symfony et JPA / Spring Data JPA côté Spring saute aux yeux. Dans les deux cas, on manipule des entités, des repositories, des relations et des mécanismes de mapping objet-relationnel.

Mais dans la pratique, le ressenti n’est pas exactement le même. Spring Data JPA pousse très loin la mécanique de repository et l’intégration à l’écosystème Spring. Doctrine, lui, reste très agréable pour un développeur PHP qui veut garder la main sur son modèle, ses requêtes, ses migrations et le découpage de son application. Là encore, il ne s’agit pas de dire que l’un est supérieur à l’autre. Ce sont deux philosophies proches, avec des sensibilités différentes.

Pour les API, les deux sont excellents

Sur la partie API, les deux mondes sont très solides. Spring propose depuis longtemps de quoi exposer des services REST, consommer d’autres APIs, brancher de la data, de la sécurité, du monitoring et des mécanismes de production-grade services. Symfony, lui, s’appuie sur son socle HTTP, son routing, ses contrôleurs, Serializer, Messenger, HttpClient et, selon les cas, API Platform pour aller très loin rapidement.

Dans la vraie vie, que l’on intègre une API CyberArk, Dynatrace, Meta, LinkedIn ou un portail open data, les enjeux sont les mêmes dans les deux mondes : authentification, résilience, mapping, gestion d’erreurs, pagination, cache, transformation des données, clarté du code et lisibilité fonctionnelle. Le framework aide, mais c’est surtout la discipline du développeur qui fait la différence.

Ce que Spring Boot m’inspire encore aujourd’hui quand je code en Symfony

Même si aujourd’hui je travaille beaucoup en PHP, je garde clairement une empreinte Java dans ma façon de penser les projets. J’aime les services clairs. J’aime les architectures propres. J’aime les couches bien découpées. J’aime les objets qui ont une responsabilité nette. J’aime les applications où l’on comprend vite où passe la logique métier.

Et je pense que c’est aussi pour cela que Symfony me plaît. Parce qu’il permet d’apporter cette rigueur dans le monde PHP sans rendre le développement pénible. On peut rester pragmatique tout en gardant une vraie tenue technique.

Une mini application “gestion des élèves d’une classe” pour comparer

Pour rendre cette comparaison concrète, prenons un exemple simple : une mini application qui gère des élèves dans une classe. L’idée est volontairement basique : créer un élève, le lister, et le rattacher à une classe. Ce n’est pas la complexité du métier qui compte ici, mais la façon dont chaque framework structure le code.

Version Spring Boot

Dans Spring Boot, on peut s’appuyer sur Spring Web et Spring Data JPA pour aller vite. Voici un exemple minimaliste avec une entité, un repository et un contrôleur REST.

package com.example.school.student;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstName;
    private String lastName;
    private String classroomName;

    public Student() {
    }

    public Student(String firstName, String lastName, String classroomName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.classroomName = classroomName;
    }

    public Long getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getClassroomName() {
        return classroomName;
    }

    public void setClassroomName(String classroomName) {
        this.classroomName = classroomName;
    }
}
package com.example.school.student;

import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository extends JpaRepository<Student, Long> {
}
package com.example.school.student;

import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/students")
public class StudentController {

    private final StudentRepository repository;

    public StudentController(StudentRepository repository) {
        this.repository = repository;
    }

    @GetMapping
    public List<Student> list() {
        return repository.findAll();
    }

    @PostMapping
    public Student create(@RequestBody Student student) {
        return repository.save(student);
    }
}

Version Symfony

Dans Symfony, on peut obtenir quelque chose de très propre avec Doctrine, les attributs PHP et un contrôleur classique. Là encore, voici une version volontairement simple et lisible.

<?php

namespace App\Entity;

use App\Repository\StudentRepository;
use Doctrine\ORM\Mapping as ORM;

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

    #[ORM\Column(length: 100)]
    private string $firstName;

    #[ORM\Column(length: 100)]
    private string $lastName;

    #[ORM\Column(length: 100)]
    private string $classroomName;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getFirstName(): string
    {
        return $this->firstName;
    }

    public function setFirstName(string $firstName): self
    {
        $this->firstName = $firstName;

        return $this;
    }

    public function getLastName(): string
    {
        return $this->lastName;
    }

    public function setLastName(string $lastName): self
    {
        $this->lastName = $lastName;

        return $this;
    }

    public function getClassroomName(): string
    {
        return $this->classroomName;
    }

    public function setClassroomName(string $classroomName): self
    {
        $this->classroomName = $classroomName;

        return $this;
    }
}
<?php

namespace App\Repository;

use App\Entity\Student;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

class StudentRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Student::class);
    }
}
<?php

namespace App\Controller\Api;

use App\Entity\Student;
use App\Repository\StudentRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;

#[Route('/api/students')]
class StudentController extends AbstractController
{
    #[Route('', methods: ['GET'])]
    public function list(StudentRepository $repository): JsonResponse
    {
        $students = $repository->findAll();

        $data = array_map(static function (Student $student): array {
            return [
                'id' => $student->getId(),
                'firstName' => $student->getFirstName(),
                'lastName' => $student->getLastName(),
                'classroomName' => $student->getClassroomName(),
            ];
        }, $students);

        return $this->json($data);
    }

    #[Route('', methods: ['POST'])]
    public function create(Request $request, EntityManagerInterface $entityManager): JsonResponse
    {
        $payload = json_decode($request->getContent(), true, 512, JSON_THROW_ON_ERROR);

        $student = new Student();
        $student->setFirstName($payload['firstName'] ?? '');
        $student->setLastName($payload['lastName'] ?? '');
        $student->setClassroomName($payload['classroomName'] ?? '');

        $entityManager->persist($student);
        $entityManager->flush();

        return $this->json([
            'id' => $student->getId(),
            'firstName' => $student->getFirstName(),
            'lastName' => $student->getLastName(),
            'classroomName' => $student->getClassroomName(),
        ], 201);
    }
}

Ce que montre cet exemple

Dans les deux cas, on retrouve les mêmes briques de fond : une entité, une couche d’accès aux données, un contrôleur HTTP et une application qui repose sur l’injection de dépendances. Ce qui change, ce n’est pas la logique métier. C’est l’ambiance générale du framework, ses conventions, son niveau de verbosité, son rapport à la configuration et le ressenti du développeur au quotidien.

Spring Boot donne une impression très nette d’écosystème intégré de bout en bout. Symfony donne une impression de grande maîtrise artisanale, mais dans le bon sens du terme : tout est là pour faire quelque chose de très propre, avec beaucoup de lisibilité.

Alors, lequel je préfère ?

Honnêtement, je ne crois plus trop aux comparaisons binaires. J’ai beaucoup de respect pour Spring Boot. C’est un environnement très fort, très mature, très rassurant pour des systèmes sérieux. Mais j’ai aussi énormément d’estime pour Symfony, parce qu’il a su apporter au monde PHP un niveau de qualité et de structure qui n’a plus rien à voir avec les vieux clichés sur le langage.

Si je regarde mon propre parcours, Java m’a appris la rigueur. PHP m’a appris le pragmatisme. Et Symfony m’a permis de réconcilier les deux.

Conclusion

Passer de Java à PHP n’a pas été pour moi un abandon de l’exigence technique. Au contraire. Cela m’a obligé à comprendre ce qui compte vraiment dans un projet : la clarté, la structure, la maintenabilité, l’architecture, la qualité du code et la capacité à faire évoluer un produit sans l’abîmer.

Spring Boot et Symfony sont, à mes yeux, deux très grands outils pour construire des applications web sérieuses. Ils n’ont pas la même histoire, pas le même langage, pas tout à fait la même culture, mais ils se respectent énormément dans leur philosophie profonde.

Et si aujourd’hui je développe surtout en PHP, je sais très bien que la part de Java que j’ai gardée en moi continue encore à influencer ma manière d’écrire du Symfony.

Sources