Mettre à jour la version de PHP dans une application existante ne consiste pas uniquement à changer l’image du conteneur ou la configuration du serveur. Le runtime interagit avec le code, les extensions, les bibliothèques Composer et les processus qui exécutent les tâches planifiées ou les travaux en arrière-plan. Un changement peut affecter chacun de ces éléments, même si l’application semble fonctionner normalement lors d’un test manuel.
Pour réduire l’incertitude, il faut traiter la mise à jour comme un changement de compatibilité : inventorier ce qui est exécuté, rechercher les incompatibilités, valider des parcours représentatifs et définir à l’avance comment décider si le déploiement se poursuit ou fait l’objet d’un retour arrière. L’objectif est d’isoler le travail nécessaire au nouveau runtime, et non de transformer la mise à jour en réécriture du produit.
Le runtime fait partie de la compatibilité de l’application

Une version de PHP détermine la syntaxe prise en charge par l’interpréteur ainsi que le comportement de certaines fonctions et de certains types. Elle détermine aussi quelles versions des extensions et des dépendances peuvent être installées. Par conséquent, le fait que le code ait fonctionné dans l’environnement actuel ne prouve pas qu’il fonctionnera dans le nouvel environnement : une fonction, une interface ou un comportement lié aux types pourrait changer, ou une extension pourrait ne plus être disponible.
Il convient de distinguer trois domaines : le code de l’application, les dépendances tierces et la configuration de l’environnement. Si les trois sont modifiés en même temps, il est plus difficile d’attribuer une défaillance à sa cause. Une mise à jour planifiée sépare ces changements lorsque c’est possible et indique explicitement quel composant a nécessité chaque ajustement.
Inventoriez le runtime, les dépendances et les processus
Avant toute modification, consignez l’environnement d’exécution réel, et pas seulement celui décrit par le fichier de configuration du projet. Vérifiez la version de PHP dans les conteneurs ou sur les serveurs qui traitent les requêtes, ainsi que dans ceux qui exécutent les tâches planifiées, les consommateurs de files d’attente et les commandes de maintenance. Ces processus peuvent utiliser des images, des variables ou des extensions différentes.
- Runtime et extensions : identifiez les extensions activées, leurs versions le cas échéant, ainsi que les bibliothèques système dont elles dépendent. Comparez les exigences de production, de CI et de développement.
- Dépendances Composer : examinez
composer.json, le fichier de verrouillage et les contraintes de version de PHP déclarées par les packages. Vérifiez également les outils de développement, comme les analyseurs et les runners de tests. - Configuration : inventoriez les valeurs de
php.ini, les limites de mémoire et de durée, la configuration des erreurs et les paramètres propres au serveur. Un nouveau runtime ne garantit pas la conservation des paramètres pertinents. - Travaux hors des requêtes web : prenez en compte cron, les files d’attente, les commandes de console, les importations, les exportations et les tâches de longue durée. Le bon fonctionnement d’un parcours web ne valide pas automatiquement ces flux.
- Intégrations et données : consignez les services externes, les formats échangés et les écritures dans les bases de données ou le stockage. Cela aide à repérer les opérations qui nécessitent une attention particulière en cas de retour arrière.
L’inventaire peut prendre la forme d’une liste conservée dans le dépôt ou dans la documentation d’exploitation, à condition de permettre la comparaison des environnements et la détection des écarts. Un signe courant d’inventaire incomplet est que CI passe, mais qu’un worker ou une tâche planifiée échoue après le déploiement.
Recherchez les incompatibilités à l’aide de plusieurs signaux
Commencez par les outils automatisés : vérifiez les contraintes de plateforme de Composer et exécutez une vérification des dépendances avec la version cible de PHP. Un conflit de résolution indique qu’un package, y compris un outil de développement, ne déclare pas sa compatibilité avec cette plateforme. Il ne faut pas forcer l’installation pour masquer le conflit sans comprendre quelle exigence est contournée.
Complétez cette analyse par les outils d’analyse statique et les tests de style ou de compatibilité disponibles dans le projet. Ils peuvent signaler des usages suspects, des API obsolètes ou des modèles qui méritent un examen, mais ne prouvent pas à eux seuls que l’application fonctionnera dans son ensemble. De même, une analyse sans anomalie ne remplace pas l’exécution réelle : certaines erreurs n’apparaissent que lorsqu’on parcourt une branche peu courante ou qu’on charge une extension.
Exécutez les tests avec le runtime cible et les extensions prévues en production. Si la suite de tests est limitée, ajoutez des vérifications manuelles ou automatisées des flux ayant le plus d’impact : authentification, opérations d’écriture, paiements le cas échéant, génération de documents et intégrations essentielles. Recueillez également les erreurs et les avertissements ; un changement qui transforme un avertissement en exception peut interrompre un parcours avant que la suite de tests ne le détecte.
Organisez le travail pour isoler les risques
Une séquence pratique consiste à commencer par confirmer l’image ou la configuration candidate et ses extensions, puis à résoudre les contraintes de dépendances et enfin à corriger le code et les paramètres qui empêchent l’exécution des tests. Faites en sorte que chaque groupe de changements puisse être examiné. Si une bibliothèque doit être mise à jour, documentez la contrainte qui impose ce changement et testez les zones de l’application où elle est utilisée.
Évitez de mettre à jour sans discernement toutes les dépendances dans la même étape. Une mise à jour étendue peut être nécessaire, mais elle augmente le nombre de causes possibles en cas de régression. Si elle ne peut pas être séparée, consignez les packages modifiés et ajoutez des tests ciblant les fonctionnalités qui en dépendent. Assurez-vous également que le fichier de verrouillage est généré et installé de manière cohérente dans CI et en production.
La configuration doit refléter la cible réelle. Valider avec une extension installée uniquement dans CI produit un signal trompeur ; il en va de même si les tâches en arrière-plan continuent de s’exécuter avec l’ancien runtime. Avant d’attribuer un résultat au code, comparez les images, les commandes de démarrage, les variables et la configuration entre l’environnement de test et celui de production.
Validez dans un environnement représentatif et définissez les critères de sortie
CI doit exécuter l’installation, l’analyse et les tests avec le runtime cible, et pas uniquement avec le runtime actuel. Ajoutez des jobs séparés pour d’autres runtimes seulement si l’application doit maintenir une fenêtre de compatibilité : dans ce cas, chaque combinaison prise en charge doit faire l’objet d’une vérification explicite. Une matrice CI peut montrer quelles combinaisons sont testées, mais elle ne couvre pas automatiquement les particularités de la production.
Utilisez un environnement de préproduction suffisamment proche de la réalité pour vérifier le démarrage, les parcours critiques, les intégrations, les files d’attente et les tâches planifiées. Examinez les journaux, les erreurs, les temps de réponse et la consommation des ressources avant et après. Définissez à l’avance quel comportement interromprait le déploiement, qui prend cette décision et pendant combien de temps le système sera observé. Les seuils doivent être fondés sur les besoins et les signaux disponibles pour l’application, et non sur des valeurs génériques.
Des critères de sortie utiles comprennent : une installation reproductible, la suite de tests convenue au vert, les flux critiques vérifiés, l’absence de nouvelles erreurs inexpliquées et la capacité à exploiter les processus en arrière-plan. Consignez les exceptions connues et la personne qui en est responsable. « Les tests passent » ne suffit pas si la suite ne couvre pas une intégration essentielle ou si l’équipe ne sait pas quelle métrique surveiller.
Déployez avec un retour arrière compatible avec les données
Si l’architecture et la plateforme le permettent, exposez progressivement le nouveau runtime : d’abord dans un environnement contrôlé, puis sur une partie du trafic ou de la capacité d’exécution. L’exposition progressive est une stratégie de déploiement, et non une divulgation d’informations. Il n’est pas toujours possible de répartir les requêtes entre plusieurs versions — par exemple, en présence de processus avec état ou de différences dans le protocole interne — ; dans ce cas, planifiez une transition coordonnée et vérifiez explicitement les consommateurs et les producteurs de messages.
Avant le déploiement, vérifiez que l’ancien code peut être exécuté à nouveau en cas de défaillance. Le retour arrière ne consiste pas seulement à restaurer une image : une migration de base de données, un nouveau format de message ou une écriture incompatible peut empêcher l’ancien runtime de lire les données créées par le nouveau. Privilégiez les changements de schéma compatibles par étapes : commencez par étendre le schéma, déployez du code capable de coexister avec les deux formes, puis retirez l’ancienne lorsque plus aucun consommateur n’en a besoin. Pour chaque étape irréversible, définissez une procédure de récupération spécifique et un critère d’arrêt.
Pendant le déploiement, surveillez les erreurs de l’application et du runtime, les défaillances des workers, le retard des files d’attente, les tâches planifiées et les indicateurs métier pertinents. Si un critère de retour arrière est atteint, arrêtez l’extension du changement et suivez la procédure testée. Conservez les journaux nécessaires pour déterminer la cause ; revenir en arrière sans établir de diagnostic risque de faire réapparaître la même défaillance lors de la tentative suivante.
Liste de contrôle pour décider si tout est prêt

- Le runtime et les extensions de tous les environnements et processus ont-ils été identifiés ?
- Les contraintes de Composer et les outils de développement ont-ils été examinés ?
- Les analyses et les tests sont-ils exécutés avec la configuration cible ?
- Les parcours critiques, les intégrations, les files d’attente et les tâches planifiées ont-ils été testés ?
- Les différences entre CI, la préproduction et la production sont-elles connues ?
- Dispose-t-on de signaux opérationnels, de responsables et de critères clairs pour poursuivre ou arrêter ?
- L’ancien code peut-il fonctionner avec les données et les messages que produira le nouveau ?
- Le retour arrière a-t-il été répété et sait-on quels changements ne peuvent pas être annulés automatiquement ?
La décision de mettre à jour la version de PHP dans une application existante est plus solide lorsque l’équipe peut répondre à ces questions en s’appuyant sur des éléments concrets. S’il manque des tests ou un inventaire, la prochaine étape n’a pas besoin d’être une réécriture : elle peut consister à combler d’abord ces lacunes et à réduire l’ampleur du changement. Ainsi, les défaillances potentielles sont détectées avant d’affecter les utilisateurs, et chaque décision de déploiement repose sur un critère vérifiable.



