Darkwood Blog Blog
  • Articles
  • Veille
  • Releases
  • CrĂ©ateurs
fr
  • de
  • en
Connexion
  • Blog
  • Articles
  • Veille
  • Releases
  • CrĂ©ateurs

đŸ—ïž OĂč doit vivre le code natif ? Phalcon, Symfony et TrueAsync Ă  diffĂ©rentes couches de la pile

le 27 juin 2026

Connectez-vous pour réagir à cet article

🚀 1

Pendant des années, Phalcon a été une réponse rationnelle pour les plateformes PHP à fort trafic : un framework livré en extension C, peu gourmand, MVC familier.

RĂ©cemment, lors d’un POC d’architecture pour un client, je me suis retrouvĂ© face Ă  une situation assez reprĂ©sentative des plateformes PHP matures : une base existante performante, des contraintes de maintenance, des workflows devenus plus complexes que le cycle requĂȘte-rĂ©ponse, et la tentation de rĂ©pondre trop vite par un choix de framework. La question visible Ă©tait : faut-il rester proche d’un modĂšle Phalcon ou reconstruire autour de Symfony ? La question rĂ©elle Ă©tait plus profonde : oĂč doivent vivre la performance native, les boundaries mĂ©tier et l’orchestration des workflows ?

Phalcon, Symfony et TrueAsync ne sont pas des concurrents directs : ils optimisent des contraintes diffĂ©rentes, Ă  des couches diffĂ©rentes de la pile. Cet article part de ce constat terrain pour proposer une lecture plus large - sans prĂ©supposer qu’une migration est toujours la bonne rĂ©ponse.

Introduction - La question n’est plus « quel framework est plus rapide ? »

Ce POC n’était pas isolĂ©. Sur une plateforme read-heavy, le dilemme se reformule souvent en termes binaires : Phalcon d’un cĂŽtĂ© - extension C, faible overhead, MVC Ă©prouvĂ© —, Symfony de l’autre - Ă©cosystĂšme, structure, recrutement plus simple —, avec TrueAsync en toile de fond comme promesse de runtime async. Chacune de ces options dĂ©fendait quelque chose de lĂ©gitime. Aucune ne rĂ©pondait seule Ă  la question qui s’imposait peu Ă  peu : Ă  quelle couche doit-on adresser la performance, et Ă  quelle couche l’orchestration ?

La discussion a vite dĂ©passĂ© le choix de framework. Faut-il rester sur une architecture proche de Phalcon, oĂč le natif vit au niveau MVC ? Migrer vers Symfony pour la maintenabilitĂ© et l’interopĂ©rabilitĂ© ? Introduire TrueAsync comme levier runtime, indĂ©pendamment de la dĂ©cision web ? Ou confondre migration framework et redessin des workflows - la erreur la plus frĂ©quente que nous voyons sur ce type de plateforme ?

La question affichĂ©e Ă©tait : « Migre-t-on de Phalcon vers Symfony ? » La question de fond est devenue : oĂč doit vivre le code natif - et oĂč doivent vivre les boundaries et les pipelines mĂ©tier ?

Trois réponses coexistent pour le natif, chacune à une couche différente :

  • Couche framework - Phalcon optimise routeur, dispatcher, ORM, cache via une extension C
  • Couche application - Symfony structure l’application en PHP pur : DI, sĂ©curitĂ©, bundles, conventions d’organisation
  • Couche runtime - TrueAsync vise l’exĂ©cution concurrente et l’I/O non bloquante via ext-async

Ces trois approches ne s’excluent pas mutuellement. Mais le POC a surtout rĂ©vĂ©lĂ© un quatriĂšme axe, souvent nĂ©gligĂ© dans les dĂ©bats « framework A vs framework B » : oĂč vivent les workflows, et comment sĂ©parer la logique mĂ©tier du modĂšle d’exĂ©cution qui la porte. Boundaries, orchestration et runtime sont trois dĂ©cisions indĂ©pendantes. Les confondre - comme le suggĂ©rait la formulation initiale du projet - mĂšne aux migrations les plus coĂ»teuses, et les moins efficaces.

Chez Darkwood, c’est cette lentille que nous essayons d’appliquer : l’industrie a longtemps optimisĂ© les frameworks ; les systĂšmes complexes exposent aujourd’hui un autre goulot - la dĂ©finition des boundaries et l’orchestration explicite. Le runtime natif reste un dĂ©tail d’implĂ©mentation, pas l’architecture. L’article qui suit gĂ©nĂ©ralise ce que ce POC a cristallisĂ© en une lecture applicable au-delĂ  d’un cas particulier.

Pourquoi Phalcon a eu du sens - et en a encore

Phalcon est un framework PHP full-stack dont le cƓur est compilĂ©. Écrit en Zephir, transpilĂ© vers du C via le projet cphalcon, il s’utilise comme n’importe quel framework PHP : controllers, services, modules. La diffĂ©rence est dans la pile : une requĂȘte HTTP arrive dans PHP-FPM, l’extension est dĂ©jĂ  chargĂ©e, et les primitives critiques - routeur, dispatcher, ORM, cache - vivent dans la couche native. Le code mĂ©tier reste en PHP ; le squelette framework est optimisĂ© en amont.

Pour une plateforme éditoriale, média ou e-commerce, les avantages restent tangibles sur le bon profil. Faible overhead sur le chemin MVC. ModÚle cohérent : modules, injection de dépendances, ORM, PHQL, Volt, cache. APIs read-heavy alimentées par des documents pré-calculés. Monolithe multi-surfaces sans empiler plusieurs stacks.

Phalcon n’était pas « plus moderne » que Symfony. Il Ă©tait plus natif au bon endroit - au niveau framework - pour un profil de charge prĂ©cis. Et pour les Ă©quipes qui maĂźtrisent cette stack, qui atteignent leurs SLOs, et dont le produit Ă©volue peu, cet avantage n’a pas disparu du jour au lendemain.

Phalcon en 2026 : maintenance, direction, crédibilité

Une lecture honnĂȘte de Phalcon en 2026 commence par les faits - pas par l’hypothĂšse d’un framework en dĂ©clin.

La branche 5.x est activement maintenue. La version 5.16.0 a Ă©tĂ© publiĂ©e en juin 2026, aprĂšs une cadence de releases accĂ©lĂ©rĂ©e au second trimestre. Les commits sur la branche 5.0.x sont frĂ©quents ; le changelog documente des Ă©volutions substantielles : couche Phalcon\Contracts, nouveau container DI, composant Auth, couche Queue (Beanstalk, Redis, Memory, Stream), support PIE pour l’installation, migration vers Zephir 1.0, outillage qualitĂ© (Infection, Sonar). Ce n’est pas la maintenance minimale d’un projet figĂ©.

L’écosystĂšme dispose d’un socle de crĂ©dibilitĂ© documentĂ©. Le fichier BACKERS.md du dĂ©pĂŽt cphalcon liste des soutiens industriels - dont Cloudflare (Ă©galement rĂ©fĂ©rencĂ© sur la page des sponsorships Cloudflare), Algolia et DigitalOcean (partenariat open source documentĂ© pour benchmarks et infrastructure). Open Collective et GitHub Sponsors alimentent un financement communautaire modeste mais rĂ©el. La gouvernance repose sur une Ă©quipe core concentrĂ©e - Nikolaos Dimopoulos et Anton Vasiliev en tĂȘte - avec des processus de contribution structurĂ©s.

Ces Ă©lĂ©ments ne prouvent pas que Phalcon est « meilleur » que Symfony. Ils prouvent qu’il ne s’agit pas d’un Ă©cosystĂšme abandonnĂ©. Un sponsor industriel n’est pas une garantie technique ; c’est un signal que le projet reste visible et soutenu par des acteurs qui croient Ă  sa pĂ©rennitĂ©.

Sur le plan architectural, cphalcon reste fondamentalement Zephir/C : plus de mille fichiers .zep, distribution en extension via PIE ou PECL. La prochaine ligne majeure en prĂ©paration est la branche 7.0.x (PHP 8.3+), pas une branche v6 dans ce dĂ©pĂŽt. Les discussions publiques et le travail sur un dĂ©pĂŽt PHP compagnon (phalcon/phalcon) suggĂšrent une Ă©volution vers un modĂšle dual-track : implĂ©mentation de rĂ©fĂ©rence en PHP, extension optionnelle pour les zones les plus coĂ»teuses - identifiĂ©es par mesure. C’est une maturation architecturale, pas un enterrement du natif.

Dimension Phalcon (v5, 2026) Symfony
Distribution Extension C (PIE / PECL) Packages Composer, PHP pur
Levier principal Overhead framework minimal Écosystùme, structure, interop
Recrutement Profils plus rares Marché large
Montée de version PHP Rebuild / repinning extension Semver Composer
Maintenance actuelle Releases fréquentes, features nouvelles Releases fréquentes, LTS
Meilleur fit Équipe experte, SLOs tenus, perf MVC critique Équipe en croissance, intĂ©grations nombreuses, churn produit

Le tableau ne désigne pas de vainqueur. Il cartographie des contraintes.

Phalcon n’est pas obsolĂšte - la cible d’optimisation a changĂ©

La mauvaise question est : « Phalcon est-il dépassé ? » La bonne question est : « Quelle optimisation compte le plus maintenant ? »

Pendant longtemps, les priorités étaient claires :

  • RĂ©duire le coĂ»t du dispatch MVC et du bootstrap framework
  • Minimiser l’overhead mĂ©moire et CPU sur le chemin requĂȘte → rĂ©ponse
  • Servir des APIs read-heavy depuis un monolithe performant sans multiplier les runtimes

Phalcon répondait à ces priorités de maniÚre cohérente. Le framework natif était le bon levier.

Les priorités ont évolué - pas parce que Phalcon a « raté » quelque chose, mais parce que les systÚmes ont grossi et les goulots ont bougé :

  • ComplexitĂ© distribuĂ©e - bus de messages, workers, modĂšles dĂ©rivĂ©s, invalidation cache Ă  grande Ă©chelle
  • Goulots I/O - agrĂ©gation HTTP, fichiers, attentes rĂ©seau dans les workers, pas seulement le temps de bootstrap
  • Orchestration - chaĂźnes de handlers, cron, scripts CLI : la logique workflow Ă©chappe au MVC
  • Onboarding et interop - recrutement, bundles, standards de sĂ©curitĂ©, intĂ©grations tierces
  • ÉvolutivitĂ© organisationnelle - bounded contexts, extraction progressive, coexistence de stacks

Sur beaucoup de plateformes matures, le routeur natif n’est plus le bottleneck mesurĂ©. L’I/O bloquante dans les workers, la complexitĂ© des workflows, ou le coĂ»t humain de la maintenance l’est. C’est ce dĂ©placement - pas un verdict de valeur - qui change la conversation architecturale.

Phalcon reste pertinent quand la contrainte dominante est encore le chemin MVC synchrone et que l’équipe maĂźtrise la stack. Symfony devient plus pertinent quand la contrainte dominante est l’organisation du code et l’écosystĂšme sur dix ans. TrueAsync entre en jeu quand la contrainte dominante est l’attente I/O dans le runtime - indĂ©pendamment du framework choisi.

OĂč doit vivre le code natif ?

Revenons Ă  la question centrale. Trois couches, trois logiques :

flowchart TB
  subgraph layers [Couches de la pile PHP]
    FrameworkLayer["Couche framework\nPhalcon extension C"]
    AppLayer["Couche application\nSymfony structure"]
    RuntimeLayer["Couche runtime\nTrueAsync ext-async"]
  end
  Question["OĂč vit le code natif ?"]
  Question --> FrameworkLayer
  Question --> AppLayer
  Question --> RuntimeLayer
Phalcon Symfony TrueAsync
Couche Framework Application Runtime
Cible Routeur, ORM, MVC, cache Structure, DI, sécurité, conventions Coroutines, I/O, pools
Question Comment rendre le framework plus rapide ? Comment organiser l’application sur le long terme ? Comment exĂ©cuter plus de travail I/O sans bloquer ?
Distribution Extension framework (PIE / PECL) Composer, PHP pur Fork PHP + ext-async
Maturité (2026) v5 maintenue, v7 en préparation Production standard Expérimental

Phalcon et TrueAsync partagent une intuition - rapprocher le travail critique du natif - mais pas le mĂȘme problĂšme. Phalcon optimise l’entrĂ©e dans le framework. TrueAsync optimise l’attente une fois dans le code mĂ©tier. Symfony, lui, ne mise pas sur le natif framework : il mise sur la structure et l’interopĂ©rabilitĂ©.

Le placement du natif est un choix d’architecture, pas une question de mode. On peut avoir du natif Ă  la couche framework sans natif au runtime. On peut introduire du runtime natif sans quitter Phalcon. On peut structurer en Symfony sans TrueAsync. Les combinaisons dĂ©pendent des contraintes mesurĂ©es - pas d’un narratif « old vs new ».

Symfony - une autre optimisation, pas un remplacement universel

Symfony est une base structurelle : HttpKernel, routing, DI, security, console, cache, Messenger, intĂ©gration Doctrine, tooling mature. Pour une plateforme qui doit documenter, auditer et faire Ă©voluer son code pendant des annĂ©es, c’est un socle organisateur crĂ©dible.

L’argument n’est pas seulement technique. C’est aussi organisationnel : recrutement plus simple, documentation abondante, intĂ©grations standards, trajectoire claire sur plusieurs versions de PHP sans dĂ©pendre d’une extension framework compilĂ©e pour chaque montĂ©e.

Mais Symfony optimise une autre contrainte que Phalcon. Il ne promet pas un routeur en C. Il promet une application maintenable, testable, intégrable - avec un écosystÚme qui absorbe une grande partie de la complexité transverse (auth, queues, observabilité, validation).

Symfony devient la bonne rĂ©ponse quand le coĂ»t dominant n’est plus le microsecond de bootstrap MVC, mais :

  • la vĂ©locitĂ© de livraison sur un produit en Ă©volution
  • la capacitĂ© Ă  recruter et former
  • l’intĂ©gration avec des services et des standards externes
  • la clartĂ© des boundaries applicatives sur le long terme

Symfony n’est pas automatiquement meilleur. C’est une autre optimisation - et elle a un coĂ»t de migration rĂ©el qu’il ne faut pas sous-estimer.

TrueAsync - runtime natif, expérimental, non automatique

TrueAsync joue un troisiĂšme rĂŽle, indĂ©pendant du choix framework. Extension PHP expĂ©rimentale (ext-async), intĂ©gration au moteur, scheduler libuv, coroutines, I/O non bloquante sur des fonctions familiĂšres (curl, fichiers, PDO dans certains cas). L’API propose spawn(), await(), delay() - sans imposer une « couleur async » Ă  chaque fonction du codebase.

Restons mesurĂ©s sur la maturitĂ©. TrueAsync est expĂ©rimental : PHP 8.6+, build custom, API en Ă©volution, RFC en cours. Ce n’est ni un standard PHP officiel, ni un substitut drop-in Ă  Swoole ou Amp. Ce n’est pas non plus « le futur » de PHP - c’est une direction Ă  Ă©valuer sur des cas prĂ©cis.

TrueAsync peut s’appliquer derriĂšre un monolithe Phalcon aussi bien que derriĂšre Symfony. Le runtime natif ne prĂ©suppose pas une migration framework. Le CRUD synchrone d’un back-office n’en a gĂ©nĂ©ralement pas besoin. Les workers I/O-heavy, les agrĂ©gations HTTP parallĂšles, les pipelines de fichiers - peut-ĂȘtre, si les mesures le justifient et si l’exploitation d’un build custom est acceptable.

Chez Darkwood, nous traitons TrueAsync comme une stratĂ©gie d’exĂ©cution - interchangeable selon le contexte - et non comme une dĂ©cision architecturale fondatrice. L’architecture, c’est le workflow et ses boundaries. Le driver async n’est que la façon dont on l’exĂ©cute.

Quand ne pas migrer hors de Phalcon

La migration n’est pas toujours souhaitable. Certaines Ă©quipes devraient rester sur Phalcon - et c’est un choix rationnel, pas un aveu d’échec.

Restez si :

  • L’équipe maĂźtrise Phalcon et la productivitĂ© est haute. Le coĂ»t de rĂ©apprentissage et de réécriture dĂ©passe le gain attendu
  • Les SLOs sont atteints - latence, dĂ©bit, stabilitĂ© - et les profils de charge n’ont pas fondamentalement changĂ©
  • Le produit Ă©volue peu - corrections, maintenance, pas de refonte majeure ni d’intĂ©grations Ă©cosystĂšme nombreuses
  • Le coĂ»t migration > valeur business - rewrite, double run, risque de rĂ©gression, gel des features pendant des mois
  • La modernisation incrĂ©mentale suffit - montĂ©e vers Phalcon 5, adoption PIE, usage des nouveaux composants (Queue, Container, Contracts) sans changer de framework

Dans ces cas, migrer vers Symfony parce que « c’est ce que font les autres » est une erreur stratĂ©gique. Phalcon v5 en 2026 n’est pas la mĂȘme chose que Phalcon 3 gelĂ© sur PHP 7 : le projet bouge, l’écosystĂšme est soutenu, et le levier framework natif reste valide tant que c’est lui le bottleneck.

Quatre trajectoires possibles

Pour une plateforme PHP Ă  grande Ă©chelle, quatre issues sont crĂ©dibles - aucune n’est la « bonne » par dĂ©faut :

1. Rester sur Phalcon et moderniser. MontĂ©e v5, adoption des nouveaux composants, refactor interne des workflows, amĂ©lioration de l’observabilitĂ©. TrueAsync optionnel sur les workers I/O-heavy si le build custom est acceptable.

2. Migrer vers Symfony. Quand les contraintes écosystÚme, recrutement ou évolution produit dominent. Migration progressive (strangler), pas big bang. TrueAsync optionnel en phase ultérieure.

3. Architecture hybride. Phalcon conserve le trafic critique ou les APIs à trÚs faible latence ; Symfony porte les nouveaux bounded contexts ou les surfaces en évolution. Coexistence assumée, avec des contrats API explicites entre les deux mondes.

4. Introduire le runtime natif indépendamment du framework. TrueAsync (ou une alternative async) sur les workers et pipelines I/O, sans toucher au framework web. Phalcon ou Symfony en couche HTTP ; le runtime async en couche exécution.

TrueAsync n’est automatiquement partie de la rĂ©ponse dans aucune trajectoire sauf la quatriĂšme - et mĂȘme lĂ , seulement aprĂšs mesure. Ce n’est pas un prĂ©requis de migration.

Boundaries avant frameworks

Voici la thĂšse que nous dĂ©fendons chez Darkwood et que nous retrouvons sur presque toutes les missions d’architecture : beaucoup de « migrations framework » sont en rĂ©alitĂ© des problĂšmes de boundaries mal dĂ©finies.

Un monolithe legacy ne souffre pas toujours parce que son routeur est lent. Il souffre parce que trois langages mĂ©tier cohabitent sans frontiĂšres claires : l’ingestion (recevoir et valider un Ă©vĂ©nement), la publication (persister et notifier), la lecture (servir une vue optimisĂ©e). Dans le code, ces trois prĂ©occupations partagent les mĂȘmes handlers, les mĂȘmes services, les mĂȘmes scripts cron. Changer de framework sans redessiner ces boundaries ne fait que dĂ©placer la dette.

Quelques concepts nous aident à nommer ce problùme - sans transformer l’article en catalogue DDD :

Bounded contexts. Chaque zone mĂ©tier a son vocabulaire et ses invariants. Sur une plateforme Ă©ditoriale, « article publiĂ© » ne signifie pas la mĂȘme chose cĂŽtĂ© ingestion (Ă©vĂ©nement Ă  traiter) et cĂŽtĂ© lecture (document prĂ©-calculĂ© Ă  servir). Les confondre dans un seul module produit les handlers enchevĂȘtrĂ©s que nous voyons partout.

Services de domaine vs services d’application. Les rĂšgles mĂ©tier (valider un contenu, calculer un statut de publication) ne devraient pas vivre au mĂȘme endroit que la coordination technique (invalider un cache, appeler un bus, reconstruire un read model). Quand tout est un « service », rien n’est testable isolĂ©ment.

Couche orchestration vs couche domaine. L’orchestration enchaĂźne les Ă©tapes ; le domaine dĂ©cide. « Persister puis invalider puis reconstruire » est de l’orchestration. « Ce contenu est-il publiable ? » est du domaine. Les mĂ©langer dans un controller ou un handler message rend les deux impossibles Ă  faire Ă©voluer sĂ©parĂ©ment.

CQRS et read models. Sur les plateformes read-heavy, le chemin d’écriture (stockage canonique) et le chemin de lecture (modĂšles dĂ©rivĂ©s, cache, documents agrĂ©gĂ©s) ont des contraintes opposĂ©es. Forcer une seule couche ORM Ă  servir les deux crĂ©e des compromis coĂ»teux. SĂ©parer explicitement write path et read path n’est pas du dogme - c’est une rĂ©ponse naturelle Ă  un profil de charge mesurĂ©.

Event-driven et cohĂ©rence Ă©ventuelle. AprĂšs une persistence, l’invalidation cache et la reconstruction du read model peuvent ĂȘtre asynchrones. C’est acceptable - Ă  condition de nommer la frontiĂšre oĂč la cohĂ©rence forte s’arrĂȘte et oĂč la cohĂ©rence Ă©ventuelle commence.

flowchart TB
  subgraph sync_boundary [Boundary synchrone]
    Validate[Validation]
    Persist[Persistence canonique]
    Validate --> Persist
  end
  subgraph async_boundary [Boundary eventual]
    Invalidate[Invalidation]
    Rebuild[Rebuild read model]
    Invalidate --> Rebuild
  end
  Persist -->|"événement"| Invalidate

La boundary synchrone - validation et persistence - doit rester ACID : soit le contenu est acceptĂ© et stockĂ©, soit l’opĂ©ration Ă©choue proprement. La boundary Ă©ventuelle - invalidation et reconstruction - peut tolĂ©rer un dĂ©lai, Ă  condition que le systĂšme de lecture le assume (stale read acceptable, ou mĂ©canisme de versioning).

Quand nous auditons une plateforme en vue de migration, la premiĂšre question n’est pas « Phalcon ou Symfony ? ». C’est : oĂč sont les boundaries aujourd’hui, et oĂč devraient-elles ĂȘtre ? Le framework n’est qu’un contenant. Un mauvais contenant propre reste prĂ©fĂ©rable Ă  un bon contenant qui recĂšle la mĂȘme confusion mĂ©tier.

Archetype PEFT - pattern plateforme éditoriale read-heavy

Pour ancrer le raisonnement sans coller Ă  une architecture rĂ©elle, imaginons la PEFT (Plateforme Éditoriale Ă  Fort Trafic) - un archetype, pas un cas client.

PEFT combine des traits communs aux grandes plateformes de contenu :

  • Chemin de lecture dominant - les APIs et le web public servent des vues prĂ©-calculĂ©es, pas la base relationnelle Ă  chaud
  • Ingestion Ă©vĂ©nementielle - un systĂšme amont Ă©met des Ă©vĂ©nements de publication ; des workers consomment, valident, persistent
  • ModĂšles dĂ©rivĂ©s - aprĂšs persistence, invalidation et reconstruction de structures de lecture optimisĂ©es (cache, documents agrĂ©gĂ©s)
  • Monolithe multi-surfaces - web, APIs, traitements batch partagent une base de code, souvent organisĂ©e en modules
  • Extraction progressive - certains bounded contexts commencent Ă  se dĂ©tacher, mais le cƓur porte encore une part significative du trafic
flowchart LR
  CMS[Source de contenu] --> Bus[Bus de messages]
  Bus --> Workers[Workers ingestion]
  Workers --> Store[(Stockage canonique)]
  Workers --> Cache[(ModÚles dérivés)]
  Cache --> APIs[APIs read-heavy]
  APIs --> Clients[Clients]

Lue avec la lentille des boundaries, PEFT révÚle trois bounded contexts implicites :

  1. Ingestion - recevoir, valider, normaliser les événements entrants
  2. Publication - persister l’état canonique, Ă©mettre les signaux de changement
  3. Lecture - servir des read models optimisĂ©s, indĂ©pendamment du schĂ©ma d’écriture

Le pattern CQRS y est naturel : le stockage canonique (write model) et les modĂšles dĂ©rivĂ©s (read models) ont des cycles de vie diffĂ©rents. L’invalidation et la reconstruction introduisent une cohĂ©rence Ă©ventuelle assumĂ©e entre Ă©criture et lecture - acceptable tant que les SLOs de fraĂźcheur sont explicites.

Sur cet archetype, les décisions architecturales ne se jouent pas sur le choix du routeur. Elles se jouent sur :

  • oĂč vit la logique d’ingestion et d’invalidation (handlers enchevĂȘtrĂ©s vs workflows explicites)
  • oĂč passe la frontiĂšre entre domaine et orchestration
  • si le bottleneck est le MVC synchrone ou l’I/O des workers
  • si le produit exige une rĂ©organisation profonde ou une stabilisation longue

PEFT peut rester sur Phalcon si les SLOs tiennent et l’équipe est stable. PEFT peut migrer vers Symfony si l’écosystĂšme et le churn produit le commandent. PEFT peut hybrider. TrueAsync n’entre en scĂšne que si les workers I/O deviennent le goulot mesurĂ© - quel que soit le framework. Mais dans tous les cas, redessiner les boundaries prĂ©cĂšde le choix technologique.

Retours d’expĂ©rience - trois archĂ©types de POC

Le POC Ă©voquĂ© en introduction - plateforme PHP Ă  fort trafic, hĂ©ritage performant, workflows qui dĂ©bordent du MVC - illustre un premier archĂ©type. Ce n’est pas le seul. Dans nos missions de conseil et validations techniques, nous retrouvons rĂ©guliĂšrement trois profils oĂč le bon premier mouvement dĂ©pend rarement du framework. Il dĂ©pend du type de dette dominante.

ArchĂ©type 1 - Monolithe legacy, rĂšgles mĂ©tier denses. C’est le cas du POC d’ouverture : plateforme mature, logique mĂ©tier enchevĂȘtrĂ©e, peu de marge pour un rewrite. L’exercice utile n’a pas Ă©tĂ© de comparer Phalcon et Symfony sur le papier, mais de cartographier les bounded contexts implicites, d’identifier les frontiĂšres de cohĂ©rence synchrone, et de proposer une extraction progressive (strangler) contexte par contexte. Le framework - Phalcon ou Symfony - est devenu secondaire : l’enjeu Ă©tait de sortir les rĂšgles mĂ©tier du magma des handlers.

ArchĂ©type 2 - Greenfield Symfony. Nouveau produit, Ă©quipe en croissance, intĂ©grations nombreuses prĂ©vues. Ici, la prioritĂ© Ă©tait la modĂ©lisation du domaine et des modules clairs - pas l’async, pas le runtime natif. Nous avons structurĂ© les boundaries tĂŽt (domain services, application services, couches de lecture distinctes) pour Ă©viter de recrĂ©er, en Symfony, le monolithe spaghetti qu’on fuyait ailleurs. Messenger a suffi pour les premiers workflows ; l’orchestration explicite n’est venue qu’avec la complexitĂ©.

ArchĂ©type 3 - Automatisation et workflows I/O-heavy. ChaĂźnes de traitement (enrichissement de contenu, appels API multiples, pipelines de fichiers - profils proches de certaines chaĂźnes IA). Le goulot n’était ni le routeur ni le modĂšle de domaine : c’était l’attente I/O et l’absence de modĂšle d’exĂ©cution explicite. Nous avons d’abord rendu le workflow lisible - Ă©tapes nommĂ©es, erreurs isolĂ©es, boundaries sync/async identifiĂ©es - puis seulement Ă©valuĂ© TrueAsync, Amp ou Fiber selon l’environnement. Introduire le runtime async avant d’avoir un workflow explicite aurait masquĂ© le vrai problĂšme.

Ces trois archĂ©types ne produisent pas le mĂȘme playbook. Ils partagent une discipline : diagnostiquer la contrainte dominante avant de choisir la technologie. C’est ce que nous appliquons chez Darkwood - sur Phalcon comme sur Symfony, avec ou sans TrueAsync.

L’orchestration comme prĂ©occupation de premier ordre

Les frameworks web - Phalcon, Symfony, Laravel - sont optimisĂ©s pour un cycle : requĂȘte HTTP → traitement → rĂ©ponse. C’est leur force. C’est aussi leur angle mort.

Les systÚmes matures dépassent vite ce cycle. Un événement de publication déclenche une chaßne : validation, persistence, invalidation cache, reconstruction de read model, notification, accusé vers un bus. Cette chaßne ne tient pas dans un controller. Elle vit éclatée entre handlers message, services, scripts CLI et tùches cron - parfois sur des années de développement, parfois sous des pressions de mise en production qui ont privilégié la vitesse sur la structure.

Nous appelons cela un problĂšme d’orchestration : la coordination explicite d’étapes mĂ©tier qui dĂ©passent le cycle requĂȘte-rĂ©ponse. Et nous pensons que ce problĂšme mĂ©rite le mĂȘme niveau de rĂ©flexion architecturale que le choix du framework.

Une architecture workflow-centric ne remplace pas le MVC. Elle le complĂšte. Le controller reste fin : il reçoit, dĂ©lĂšgue, rĂ©pond. Le workflow porte la logique multi-Ă©tapes : il nomme les Ă©tapes, gĂšre les erreurs par Ă©tape, dĂ©finit les boundaries de cohĂ©rence, et - idĂ©alement - sĂ©pare la description du pipeline du modĂšle d’exĂ©cution qui le fait tourner.

C’est lĂ  que nous divergeons des approches « tout dans Messenger » ou « tout dans un service god-object ». Messenger transporte des messages ; il n’orchestrre pas nativement un pipeline multi-Ă©tapes avec stratĂ©gies d’exĂ©cution interchangeables. Un service de 800 lignes qui fait tout orchestre, mais de façon opaque et non testable.

Chez Darkwood, nous plaçons l’orchestration au mĂȘme niveau que les boundaries et le choix framework. Pas parce qu’un seul outil rĂ©sout tout - mais parce que ne pas nommer l’orchestration est la cause la plus frĂ©quente des migrations ratĂ©es. On change de framework ; les handlers restent enchevĂȘtrĂ©s ; la dette suit.

Flow - sĂ©parer le workflow du modĂšle d’exĂ©cution

C’est cette observation qui nous a conduits Ă  dĂ©velopper Flow - un composant open source, pas un framework de remplacement.

Flow existe parce que nous avons vu, sur des migrations rĂ©elles, le mĂȘme pattern se rĂ©pĂ©ter : la logique workflow n’a pas de maison naturelle dans Symfony ou Phalcon. Elle finit dans des handlers anonymes, des scripts cron ou des services fourre-tout. Flow lui donne une place architecturale : un pipeline explicite composĂ© de Flow (l’étape), Job (le travail unitaire) et Ip (le jeton de donnĂ©es qui traverse le pipeline).

Mais le différenciateur architectural le plus important, pour nous, est DriverInterface.

MĂȘme workflow. ModĂšle d’exĂ©cution interchangeable.

Un pipeline de publication - valider, persister, invalider, reconstruire - peut s’exĂ©cuter en synchrone pur, en fibers PHP, en coroutines Amp, sur une event loop ReactPHP, dans un worker Swoole, ou via TrueAsync. Le mĂ©tier ne change pas. Seul le modĂšle d’exĂ©cution change. C’est une dĂ©cision d’infrastructure, pas de domaine.

Flow propose aujourd’hui plusieurs drivers : FiberDriver (dĂ©faut, pas d’extension), AmpDriver, ReactDriver, SwooleDriver, SpatieDriver, ParallelDriver, et TrueAsyncDriver (expĂ©rimental, ext-async). Chacun rĂ©pond Ă  un contexte d’exploitation diffĂ©rent - intĂ©gration existante, worker dĂ©diĂ©, I/O natif expĂ©rimental.

use Flow\Driver\FiberDriver;
use Flow\Driver\TrueAsyncDriver;
use Flow\Flow\Flow;
use Flow\Ip;

// Le workflow est stable ; seul le driver change selon l'environnement
$driver = TrueAsyncDriver::isSupported()
    ? new TrueAsyncDriver()
    : new FiberDriver();

$flow = (new Flow(job: new ValidateMessage(), driver: $driver))
    ->fn(new Persist())            // domaine : boundary synchrone
    ->fn(new InvalidateCache())    // orchestration
    ->fn(new RebuildReadModel());  // I/O potentiellement async

$flow(new Ip($message));
$flow->await();

Symfony reçoit l’évĂ©nement - via Messenger ou un endpoint interne - et dĂ©lĂšgue Ă  Flow. Chaque fn() est une Ă©tape nommĂ©e ; les erreurs peuvent ĂȘtre isolĂ©es par errorJob. On ne commence pas par TrueAsync : FiberDriver par dĂ©faut, mesure, puis opt-in sur le pipeline qui le justifie.

Points d’attention que nous appliquons en production : ne pas mĂ©langer FiberDriver et TrueAsyncDriver dans le mĂȘme processus (TrueAsync bloque les fibers userland tant qu’il est actif). Ne pas introduire threads, channels ou TaskGroup dans un premier temps - complexitĂ© d’exploitation sans besoin dĂ©montrĂ©.

Flow n’est pas la seule rĂ©ponse possible. Symfony Messenger, un pipeline maison, ou une orchestration par Ă©vĂ©nements peuvent suffire sur des workflows simples. Flow explore une direction plus ambitieuse : faire de l’orchestration une primitive architecturale de premier ordre, avec sĂ©paration explicite entre le quoi (le pipeline) et le comment (le driver).

Nous ne disons pas que Flow est le futur. Nous disons que l’orchestration explicite - avec la possibilitĂ© de changer de stratĂ©gie d’exĂ©cution sans réécrire le mĂ©tier - est une direction que les systĂšmes complexes nous ont appris Ă  prendre au sĂ©rieux.

Si vous choisissez de migrer - principes, pas playbook

Quand la trajectoire « migrer vers Symfony » est choisie - et seulement alors - quelques principes valent mieux qu’un plan en cinq phases rigide.

Mesurer avant de bouger. Identifier les vrais bottlenecks : MVC, workflows, I/O workers, couplage Volt/PHQL, boundaries floues. Ne pas migrer un framework performant pour rĂ©soudre un problĂšme d’orchestration ou de modĂ©lisation.

Redessiner les boundaries d’abord. Avant de réécrire un module, nommer ses bounded contexts, ses read models, ses frontiĂšres de cohĂ©rence. Le strangler fonctionne par contexte, pas par couche technique.

Strangler, pas big bang. Nouvelle application Symfony en parallÚle ; routage progressif endpoint par endpoint. Préserver les contrats API pendant la coexistence.

Sync d’abord, async ensuite. Extraire les workflows en synchrone. Rendre la chaüne lisible et testable avant d’introduire TrueAsync ou tout autre runtime async.

Opt-in sur l’async. TrueAsync sur les pipelines I/O-heavy uniquement, en environnement dĂ©diĂ©, avec repli possible.

Les patterns legacy se dĂ©placent diffĂ©remment selon leur nature : les handlers en chaĂźne vers un workflow explicite ; les modules applicatifs vers des bundles ou dossiers Feature/ ; l’invalidation cache ad hoc vers un pipeline nommĂ© ; l’I/O bloquante dans les workers vers un runtime async opt-in ; l’ORM/PHQL vers Doctrine - souvent la migration la plus coĂ»teuse, Ă  traiter Ă  part.

Un endpoint CRUD se porte en controller Symfony simple. Une chaĂźne ingestion → cache → modĂšle dĂ©rivĂ© mĂ©rite une rĂ©flexion workflow - et probablement des boundaries redessinĂ©es avant tout choix d’outil.

Ce qu’il ne faut pas faire

Certaines erreurs reviennent - y compris quand la migration n’est pas nĂ©cessaire.

Migrer par dĂ©faut parce que Phalcon « fait vieux » - alors que v5 est maintenue, les SLOs tiennent et l’équipe est productive.

Ignorer Phalcon v5 moderne - Queue, Container, Contracts, PIE - et traiter le framework comme figé sur une version ancienne.

Changer de framework sans redessiner les boundaries - le monolithe spaghetti survit au changement de namespace.

DĂ©ployer TrueAsync partout - ignore sa maturitĂ© expĂ©rimentale et alourdit l’exploitation.

Confondre concurrence I/O et parallélisme CPU - mÚne à de mauvais choix, quel que soit le framework.

Transformer une lib d’orchestration en framework - pipeline systĂ©matique sur chaque feature remplace un anti-pattern par un autre.

PrĂ©senter TrueAsync comme prĂȘt pour la production universelle - en 2026, c’est une piste Ă  cadrer et Ă  tester.

Introduire l’async avant d’avoir un workflow explicite - masque la dette d’orchestration derriĂšre une couche d’exĂ©cution.

Risques réalistes

Risque Mitigation
Migration sous-estimĂ©e Strangler ; pĂ©rimĂštre par endpoint ; boundaries d’abord
Boundaries mal définies Cartographie contexts avant rewrite ; CQRS explicite si read-heavy
API TrueAsync instable Driver optionnel ; repli Fiber ; version épinglée
Build PHP custom Limiter aux workers / environnements dédiés
Doctrine + concurrence EM par unité de travail ; transactions courtes
Coexistence Phalcon / Symfony Contrats API explicites ; routage clair ; observabilité
Sur-ingénierie orchestration Pipelines sur workflows réels uniquement

Conclusion - au-delà du framework, l’orchestration explicite

Phalcon n’a jamais Ă©tĂ© une erreur. Pour des plateformes read-heavy, optimiser le framework en C Ă©tait une rĂ©ponse cohĂ©rente - et reste dĂ©fendable quand la contrainte dominante est encore le chemin MVC.

Symfony n’est pas automatiquement meilleur. C’est une optimisation diffĂ©rente : structure, Ă©cosystĂšme, maintenabilitĂ© organisationnelle. Pertinent quand ces contraintes dominent le coĂ»t du framework natif.

TrueAsync n’est pas automatiquement le futur. C’est une optimisation runtime expĂ©rimentale - pertinente sur certains profils I/O, indĂ©pendante du choix framework, pas un prĂ©requis de modernisation.

Phalcon, Symfony et TrueAsync placent le natif - ou la structure, ou l’async - Ă  des couches diffĂ©rentes de la pile. Mais la compĂ©tence architecturale, en 2026, ne s’arrĂȘte pas lĂ .

L’industrie a passĂ© des annĂ©es Ă  optimiser les frameworks. La frontiĂšre suivante, pour les systĂšmes complexes, n’est pas seulement la performance framework : c’est l’orchestration explicite, les boundaries de domaine clairement tracĂ©es, et les stratĂ©gies d’exĂ©cution interchangeables selon le contexte. Le runtime natif est un levier d’implĂ©mentation. L’orchestration est une dĂ©cision d’architecture.

Chez Darkwood, nous construisons Flow parce que les systĂšmes matures nous ont appris une chose : quand les workflows dĂ©passent le cycle requĂȘte-rĂ©ponse, il faut leur donner une place architecturale - et sĂ©parer la logique d’exĂ©cution du mĂ©tier qu’elle coordonne. Flow explore une direction oĂč l’orchestration devient une primitive de premier ordre, pas un assemblage de handlers et de cron.

Le choix framework reste important. Il n’est qu’une partie de l’équation. La vraie question n’est pas seulement « oĂč vit le code natif ? » - c’est aussi oĂč vivent les workflows, oĂč passent les boundaries, et qui porte la responsabilitĂ© de l’orchestration dans une architecture qui doit tenir dix ans.

Sources

Cet article s’appuie sur plusieurs sources publiques, expĂ©rimentations personnelles et travaux open source autour de l’architecture PHP moderne, de l’exĂ©cution asynchrone et de l’orchestration de workflows.

Frameworks et runtime

  • Phalcon Framework (site officiel) : documentation officielle, historique du framework et architecture Zephir/C.
  • Symfony Framework : rĂ©fĂ©rence pour l’écosystĂšme PHP orientĂ© maintenabilitĂ© et architecture applicative.
  • TrueAsync documentation : documentation du runtime async expĂ©rimental basĂ© sur ext-async.

Références Darkwood

Une partie des rĂ©flexions prĂ©sentĂ©es ici provient de travaux menĂ©s chez Darkwood autour de la sĂ©paration entre workflow mĂ©tier et modĂšle d’exĂ©cution.

  • Flow - Darkwood orchestration library : ImplĂ©mentation open source de pipelines mĂ©tier avec drivers d’exĂ©cution interchangeables (Fiber, Amp, ReactPHP, Swoole, Parallel, TrueAsync). Le support expĂ©rimental de TrueAsyncDriver y est disponible comme preuve de concept pour explorer l’orchestration dĂ©couplĂ©e du runtime.
  • Slidewire presentation source : Les slides de la prĂ©sentation associĂ©e Ă  cet article, construites avec Slidewire, sont disponibles publiquement dans ce dĂ©pĂŽt.

Connectez-vous pour réagir à cet article

🚀 1

Site

  • Plan du Site
  • Contact
  • Mentions lĂ©gales

Network

  • Hello
  • Blog
  • Apps
  • Photos

Social

Darkwood 2026, tous droits réservés