Contact salesFree trial
Blog

Créer des CLIs hybrides PHP-Go avec Symfony Console

CLIGoPHPSymfony
Share

Pour une lecture rapide des principaux points à retenir, continuez à faire défiler le texte. Nous avons utilisé ChatGPT pour améliorer la grammaire et la syntaxe.

Introduction

Lorsque vous utilisez une plateforme orientée développeur depuis plus d'une décennie, votre outillage a tendance à accumuler un certain bagage. Nous nous sommes retrouvés avec une interface de ligne de commande (CLI) entièrement implémentée en PHP - un choix naturel à l'époque, étant donné nos liens étroits avec les écosystèmes PHP et Drupal. Cependant, au fur et à mesure que notre public et les langages pris en charge s'élargissaient, nous avons réalisé que nous devions repenser la façon dont notre CLI était construite et distribuée.

  • Nous voulions un binaire unique que tout le monde puisse installer - pas de dépendances linguistiques supplémentaires.
  • Nous voulions conserver l'ensemble des commandes (et l'expérience utilisateur) de notre ancien CLI basé sur PHP.
  • Nous voulions de meilleures performances et un support multiplateforme plus facile, ce qui nous a conduit à Go.

Le résultat ? Un CLI hybride qui intègre la logique de notre CLI PHP existante dans un nouveau binaire basé sur Go, associé à Symfony Console pour un routage cohérent des commandes, l'autocomplétion et les raccourcis. Voici notre histoire, comment nous sommes arrivés là, pourquoi nous avons pris certaines décisions, et ce que nous avons appris en cours de route.

Pourquoi nous avions besoin d'un CLI hybride

À l'origine, notre CLI était écrit en PHP, ce qui convenait parfaitement à notre principale base d'utilisateurs de l'époque. Au fur et à mesure de notre croissance, les technologies de nos utilisateurs se sont développées : Node.js, Python, Go, Ruby, Symfony, etc. Nous devions fournir une expérience CLI aux équipes qui n'avaient peut-être pas installé PHP - et qui ne voulaient pas non plus l'installer juste pour exécuter un outil.

Les objectifs clés qui nous ont poussés à reconsidérer notre approche CLI:

  1. Compatibilité ascendante. Nous ne pouvions pas abandonner notre CLI PHP existant et interrompre les flux de travail de tout le monde.
  2. La performance sans sacrifier la fonctionnalité. Nous voulions un temps de démarrage plus rapide et un ensemble de fonctionnalités robustes.
  3. Plus de dépendance forcée à PHP. L'installation de l'interface de programmation doit fonctionner sur n'importe quel système d'exploitation ou architecture.

Le choix de Go pour la nouvelle interface de programmation

Go est largement utilisé dans l'écosystème des outils de développement (par exemple, Docker, Terraform et d'innombrables autres outils en ligne de commande). Il se compile en un seul binaire statique qui s'exécute rapidement et est facile à distribuer pour Linux, macOS et Windows. Telles étaient nos principales motivations :

  1. Distribution d'un seul binaire. Pas de dépendances supplémentaires, installation simple.
  2. Compilation multiplateforme. Compilation unique pour chaque cible - pas de chaînes de compilation compliquées ni d'outils externes nécessaires.
  3. Vitesse. Le temps de démarrage et le modèle de concurrence de Go permettent à l'interface de programmation d'être plus réactive.

Comment exécuter PHP à partir de Go (oui, vraiment)

Nous avions encore besoin de tout notre code PHP existant - des milliers de lignes de logique - disponible pour les utilisateurs. Mais comment l'exécuter à l'intérieur d'un binaire Go sans avoir besoin d'un PHP séparé sur la machine de l'utilisateur ?

  1. En intégrant un binaire PHP minimal. Nous avons construit une version simplifiée de PHP avec seulement les extensions dont notre CLI avait besoin.
  2. Nous l'avons intégré dans le binaire Go. Lorsque l'utilisateur exécute une commande "legacy", Go fait appel à cet interpréteur PHP intégré.
  3. Routage des commandes "anciennes" par rapport aux commandes "nouvelles". S'il s'agit d'une commande ancienne, lancer l'interpréteur PHP intégré. S'il s'agit d'une de nos nouvelles fonctionnalités, il faut s'en tenir à Go.

Cette configuration nous a permis de ne pas avoir à réécrire immédiatement toutes les commandes existantes. En intégrant PHP, tout continuait à fonctionner, mais nous pouvions toujours ajouter de nouvelles fonctionnalités en Go sans retarder la sortie de la version complète.

Symfony Console (en Go !)

Nous nous sommes appuyés sur Symfony Console dans notre CLI original basé sur PHP pour les arguments, les raccourcis et l'autocomplétion. Nous voulions conserver cette expérience utilisateur familière - des raccourcis comme p:init pour project:init, ou des textes d'aide bien structurés, etc.

Il s'avère que le CLI officiel de Symfony est écrit en Go, et qu'il inclut un composant Symfony Console basé sur Go. En remplaçant notre ancienne bibliothèque Go (Cobra) par cette Console Symfony pour Go, nous avons gagné :

  • Routage cohérent des commandes. Charger toutes les commandes, les analyser au même endroit, puis décider si c'est Go ou PHP qui les traitera.
  • Autocomplétion. La Console Symfony s'occupe de la génération de la complétion, donc nous exposons juste la liste complète des commandes.
  • Raccourcis familiers. Obtenez la même expérience conviviale que nous avions dans l'interface de commande PHP.

Déploiement de la nouvelle CLI

  1. L'ancienne CLI reste principale dans un premier temps. Nous avons continué à maintenir l'interface de programmation de PHP pour nous assurer que rien n'était cassé pour les utilisateurs existants.
  2. De nouvelles commandes font leur apparition dans Go. Nous avons ajouté de nouvelles commandes spécialisées (par exemple, project:init, validate) dans le nouveau code Go.
  3. Migration progressive. Au fil du temps, nous déplacerons les anciennes commandes PHP dans la base de code Go. Pendant ce temps, le CLI reste un binaire unique.

Bien sûr, maintenir deux bases de code (le PHP intégré pour les anciennes commandes et le nouveau code Go) demande du travail supplémentaire. Mais cela nous donne aussi la liberté d'avancer à notre propre rythme, en nous assurant que chaque fonctionnalité est testée en profondeur sans forcer une réécriture massive.

Tests, tests, tests

Nous n'avons jamais voulu interrompre les flux de production des développeurs :

  • Lestests d'intégration garantissent que chaque commande de la nouvelle CLI se comporte exactement comme dans l'ancienne (même entrée, même sortie).
  • Lestests unitaires pour nos commandes Go permettent de détecter toute régression des nouvelles fonctionnalités.
  • Les tests de bout en bout basés sur des sim ulacres font tourner des serveurs fictifs pour valider les flux réels, de l'appel initial à la sortie finale.

Les prochaines étapes

Nous migrons régulièrement d'autres commandes vers Go, en particulier celles qui requièrent une authentification. Une fois cette étape franchie, nous pourrons unifier la gestion des identifiants et des jetons dans le nouveau binaire, ce qui pourrait améliorer la gestion des clés SSH et l'intégration du stockage sécurisé. Nous explorons également les moyens de permettre aux développeurs tiers d'étendre la CLI, maintenant que la base de code est plus modulaire.

Conclusion

La réécriture d'un CLI mature est rarement simple, surtout lorsque des milliers de développeurs s'y fient quotidiennement pour leurs flux de production. En adoptant une architecture hybride, nous avons conservé les fonctionnalités existantes basées sur PHP, amélioré considérablement la distribution (un seul binaire, pas de dépendances linguistiques) et jeté les bases de futures extensions en Go.

Principaux enseignements:

  1. Les approches hybrides permettent de gagner du temps. Il n'est pas nécessaire de réécrire des milliers de lignes de code du jour au lendemain.
  2. Il est possible d'intégrer des interprètes. Si vous avez besoin de langages ou de frameworks plus anciens, l'envoi de petites constructions curatives peut s'avérer étonnamment efficace.
  3. Le test est roi. Dans un environnement hybride, les tests d'intégration et de bout en bout sont essentiels pour éviter les régressions.

Nous espérons que ce voyage vous inspirera si vous êtes confronté à un dilemme similaire : héritage contre futur. Que vous exploriez de nouveaux langages, de nouveaux modèles de distribution ou des moyens d'unifier l'expérience de vos développeurs, un CLI hybride pourrait être exactement ce dont votre équipe a besoin.

Votre meilleur travail
est à l'horizon

Essai gratuit
Discord
© 2025 Platform.sh. All rights reserved.