Blog

Guide de Migration PHP : Passer à PHP 8.4 et PHP 8.5

Guide technique pour migrer vers PHP 8.4 et 8.5 : Rector, mise à jour des environnements, PHPUnit et déploiement en production. Étape par étape.

Mathieu Ducrot Mathieu Ducrot
|
|
11 min de lecture
| Tech
Résumez cette page avec votre IA préférée :
Migrer vers PHP 8.4 et 8.5 : guide technique étape par étape

PHP 8.4 est sorti en novembre 2024, PHP 8.5 en novembre 2025. Si votre projet tourne encore sur une version antérieure, chaque mois de retard est une fenêtre de vulnérabilité ouverte en production.

Votre point de départ ?

  • Vous êtes sur PHP 8.3 : ce guide s’adresse directement à vous. Le passage vers 8.4 puis 8.5 est une évolution sans rupture, Rector automatise l’essentiel des corrections.
  • Vous êtes sur PHP 8.2 suite à votre migration de Symfony 6 vers Symfony 7 (qui impose PHP 8.2 au minimum) : ce guide s’applique aussi. Rector gère les dépréciations accumulées depuis 8.2 automatiquement, sans étape intermédiaire nécessaire.
  • Vous êtes encore sur PHP 7.x, 8.0 ou 8.1 : consultez d’abord notre guide Migration PHP 7 vers 8 avant de revenir sur ces étapes.

Les dates de fin de support sécurité à retenir :

  • PHP 8.2 : novembre 2026 -> cette année
  • PHP 8.3 : novembre 2027
  • PHP 8.4 : novembre 2028
  • PHP 8.5 : novembre 2029

PHP 8.4 et 8.5 sont des versions d’évolution, pas de rupture. La grande majorité des projets PHP bien tenus passent sans toucher au code métier. Ce guide détaille la méthode que nous appliquons chez SmartBooster, pas à pas, avec Rector comme outil principal d’automatisation.

Sommaire de la migration

  1. Vérifier la compatibilité de vos extensions PHP
  2. Corriger les changements de comportement avec Rector
  3. Mettre à jour vos dépendances Composer
  4. Mettre à jour vos environnements
  5. Mettre à jour PHPUnit en parallèle
  6. Documenter la migration dans le maintenance.md
  7. Valider et déployer en production

1. Vérifier la compatibilité de vos extensions PHP

Avant toute chose, l’audit des dépendances est la première étape. Certaines extensions PHP (intl, imagick, redis, xdebug…) ont leur propre cycle de versions et peuvent ne pas être encore compilées pour PHP 8.4 selon votre distribution.

Côté Composer, un outil dédié :

composer require --dev phpcompatibility/php-compatibility
vendor/bin/phpcs --standard=PHPCompatibility --extensions=php --runtime-set testVersion 8.4 src/

Plus simplement, un composer update --dry-run après avoir changé la contrainte PHP dans composer.json (voir étape 3) suffit → Composer liste directement les paquets bloquants.


2. Corriger les changements de comportement avec Rector

Nous continuons par corriger les dépréciations dans le code. PHP 8.4 introduit plusieurs dépréciations qui génèrent des Deprecated notices en production si elles ne sont pas corrigées avant la mise à jour.

Plutôt que de les corriger manuellement fichier par fichier, Rector automatise l’essentiel du travail.

Installer Rector

composer require --dev rector/rector

Configurer rector.php

À la racine du projet, le fichier rector.php est créé ou mis à jour :

<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/config',
        __DIR__ . '/public',
        __DIR__ . '/src',
        __DIR__ . '/tests',
    ])
    ->withPhpVersion(PhpVersion::PHP_84)
;

Le PhpVersion::PHP_84 applique toutes les règles cumulatives depuis PHP 5.3 jusqu’à 8.4. Il est idempotent : sur un code déjà en 8.3, seules les règles 8.4 s’appliquent effectivement.

Lancer Rector en mode preview (sans modification)

vendor/bin/rector process --dry-run

Le diff proposé est à relire attentivement, Rector montre exactement ce qu’il va modifier avant d’écrire quoi que ce soit.

Appliquer les corrections

vendor/bin/rector process

Vérifier et committer

git diff
git add -p  # Revue fichier par fichier si besoin
git commit -m "fix: apply Rector PhpVersion::PHP_84 ruleset"

Le changement majeur : les types nullable implicites

La dépréciation la plus fréquente en PHP 8.4 concerne les paramètres implicitement nullable :

// Avant (PHP 8.3 : pas d'erreur, PHP 8.4 : Deprecated)
function save(string $comment = null): void {}

// Après (correct depuis PHP 7.1)
function save(?string $comment = null): void {}

Rector corrige automatiquement ces cas avec la règle NullToStrictStringFuncCallArgRector incluse dans PhpVersion::PHP_84. Sur un projet de taille moyenne, cela représente plusieurs dizaines de corrections dans les entités, services et formulaires Symfony.

Il est aussi possible de cibler uniquement cette règle pour un premier passage chirurgical :

vendor/bin/rector process --only=Rector\\Php81\\Rector\\FunctionLike\\NullToStrictStringFuncCallArgRector

Les autres dépréciations notables de PHP 8.4

  • E_STRICT supprimé : la constante existe toujours mais n’est plus levée.
  • exit() / die() deviennent des vraies fonctions : ils peuvent maintenant être passés comme callbacks.
  • GMP integer overflow : le comportement silencieux sur les dépassements est déprécié.
  • DOM extension : plusieurs méthodes dépréciées en faveur de l’API HTML5 native.

La liste complète est disponible dans le guide officiel de migration PHP 8.4.


3. Mettre à jour vos dépendances Composer

Prochaine étape mettre à jour les dépendances encore sur PHP 8.3 pour minimiser les impacts lors du changement de version. L’objectif est double : certains Deprecated proviennent des vendors eux-mêmes et disparaissent simplement en mettant à jour les paquets, et les montées de version mineures préparent la compatibilité PHP 8.4.

Premier passage : patch updates de toutes les dépendances

On commence par un composer update classique pour pousser toutes les dépendances existantes à leur dernière version de patch, sans changer les contraintes de composer.json. Cela corrige silencieusement des dépréciations qui viennent des vendors :

composer update

Second passage : montées de version pour PHP 8.4

Certaines librairies requièrent une version mineure ou majeure spécifique pour fonctionner sous PHP 8.4.

Par exemple si vous êtes sur projet full php et que vous souhaitez ajouter ou utiliser le composat symfony/console vous devez spécifier la version 8 qui est la seul compatible selon son composer.json sur php 8.4

composer require symfony/console:^8.0

4. Mettre à jour vos environnements

Les dépréciations sont corrigées, les vendors sont à jour : on bascule maintenant les environnements sur PHP 8.4. La mise à jour doit se faire de manière progressive : local, CI, recette et production. L’écart entre versions est la première source de bugs difficiles à reproduire.

En local (Docker)

Chez SmartBooster, les projets tournent dans des conteneurs Docker. La version de PHP est pilotée par la variable d’environnement PHP_VERSION interprétée par notre Dockerfile. Pour passer en 8.4, nous modifions le fichier .env du projet :

PHP_VERSION=8.4

Puis nous rebuildons l’image pour prendre le changement en compte :

docker compose down && docker compose up -d --build

Enfin pour vérifier la version active, on lance php directement dans le conteneur :

docker compose exec php php -v

C’est aussi le moment de déclarer la contrainte PHP dans composer.json pour que Composer vérifie la compatibilité de tous les paquets futurs :

"require": {
    "php": ">=8.4",
    ...
}

Pendant l’intégration continue (GitLab CI)

Sur nos projets clients, la CI GitLab s’appuie sur une image Docker construite à partir du Dockerfile de dev du projet. Lors d’une montée de version PHP, on lance manuellement le job build-image pour régénérer l’image avec la nouvelle version, qui sera ensuite utilisée par tous les jobs de la pipeline :

build-image:
  stage: build-test
  image: docker
  services:
    - docker:dind # docker in docker
  before_script:
    - '[ -f .env ] && export $(grep -v "^#" .env | xargs) || echo ".env file not found"'
  script:
    - echo $PHP_VERSION
    - echo $NODE_VERSION
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
    - docker build --build-arg PHP_VERSION=$PHP_VERSION --build-arg NODE_VERSION=$NODE_VERSION -t $CI_REGISTRY_IMAGE .
    - docker push $CI_REGISTRY_IMAGE
  when: manual

La variable PHP_VERSION est directement reprise du fichier .env versionné dans le projet. Il suffit de la passer à 8.4 et de déclencher le job pour que l’image soit reconstruite et poussée dans le registry.

Sur la CI côté open source (GitHub Actions)

Sur nos repositories open source, on profite de la matrix strategy de GitHub Actions pour tester plusieurs versions de PHP en parallèle et garantir la compatibilité :

jobs:
    ci:
        runs-on: ubuntu-latest
        strategy:
            matrix:
                php: [
                    '8.3',
                    '8.4'
                ]

Chaque entrée de la matrice déclenche un job indépendant : on valide ainsi que le code tourne sur 8.3 et 8.4 sans avoir à maintenir deux pipelines distinctes.

Au moment du déploiement sur Clever Cloud (de la pré-prod à production)

Sur Clever Cloud, la version de PHP est pilotée par la variable d’environnement CC_PHP_VERSION. Dans la console Clever Cloud, on modifie la variable dans l’onglet Variables d’environnement de l’application :

CC_PHP_VERSION=8.4

Un redéploiement applique immédiatement le changement. Nous procédons d’abord sur les environnements de pré-production (intégration, recette) pour valider avant la production.


5. Mettre à jour PHPUnit en parallèle

La migration PHP 8.4 est aussi le bon moment pour remettre à jour PHPUnit, qui évolue indépendamment mais dont certaines APIs sont alignées sur PHP 8.x.

Passer à PHPUnit 12.2

Dans phpunit.xml, la variable d’environnement utilisée par symfony/phpunit-bridge est mise à jour :

<server name="SYMFONY_PHPUNIT_VERSION" value="12.2" />

La contrainte est ajoutée dans composer.json si besoin :

composer require --dev symfony/phpunit-bridge:^7.0 --no-update
composer update symfony/phpunit-bridge

Adapter la configuration phpunit.xml

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="vendor/bin/.phpunit/phpunit.xsd"
    backupGlobals="false"
    colors="true"
    bootstrap="tests/bootstrap.php"
    displayDetailsOnTestsThatTriggerDeprecations="false"
    displayDetailsOnTestsThatTriggerErrors="true"
    displayDetailsOnTestsThatTriggerNotices="true"
    displayDetailsOnTestsThatTriggerWarnings="true"
>

Les options --colors=never sont à supprimer si elles étaient présentes dans les Makefile ou scripts CI car elles rentrent en conflie avec celle décrit dans la configuration xml.

Migrer les Data Providers vers les attributs

PHPUnit 12 abandonne définitivement les annotations @dataProvider au profit des attributs PHP 8 :

// Avant
/**
 * @dataProvider fooProvider
 */
public function testFoo(...): void {}

// Après
#[DataProvider('fooProvider')]
public function testFoo(...): void {}

Les méthodes providers doivent également être déclarées static :

public static function fooProvider(): array
{
    return [
        ['value1'],
        ['value2'],
    ];
}

Compatibilité setOutputCallback

Si les tests d’availability utilisent setOutputCallback, l’appel est protégé pour rester compatible :

if (method_exists($this, 'setOutputCallback')) {
    $this->setOutputCallback(function () {
        return null;
    });
}

Mettre à jour PHPStan en parallèle

C’est également le bon moment pour passer PHPStan en version 2 si ce n’est pas déjà fait :

composer require --dev phpstan/phpstan:^2.0 --no-update
composer update phpstan/phpstan

Le fichier phpstan.neon est ajusté pour les options compatibles v2 :

parameters:
    reportUnmatchedIgnoredErrors: false
    symfony:
        containerXmlPath: var/cache/dev/App_KernelDevDebugContainer.xml

6. Documenter le suivis de sa migration

Chez SmartBooster, chaque opération de maintenance technique (comme les montée de version PHP, mise à jour de dépendances, correction de dépréciations) est tracée dans un fichier maintenance.md versionné dans le dépôt Git du projet et mis à disposition du client.

L’objectif est double : transparence totale sur ce qui a été fait et pourquoi, et traçabilité pour quiconque reviens sur le projet.

Structure d’une entrée de migration

## 2026
### Mars
#### Mises à jour des dépendances
- Mise à jour [PHP](https://www.php.net/supported-versions.php) de 8.2 vers 8.4 (via process interne de migration + rector)

#### Nettoyage de code obsolète
- Suppression des annotations autogénérées en entête des repositories pour simplifier les montées de versions

#### Mise à jour outils mesure de la qualité et déploiement
- Mise à jour [Stack Docker](https://github.com/smartbooster/symfony-docker) de 1.0.11 vers 1.2.5

Pourquoi c’est important ?

Un maintenance.md bien tenu répond aux questions courantes :

  • “Quand a été faite la dernière mise à jour de PHP ?” → réponse immédiate
  • “Pourquoi a-t-on changé cette dépendance ?” → contexte conservé
  • “Le projet est-il à jour ?” → historique visible (même sans accès direct au repository)

C’est aussi un outil de pilotage : en listant les opérations de maintenance effectuées et leur fréquence, il permet d’anticiper les prochaines échéances (fin de vie PHP 8.4 en décembre 2028, prochain LTS Symfony, etc.).


7. Valider et déployer en production

Relancer la suite de tests complète

php bin/phpunit

Un passage au vert complet valide la migration. Si des dépréciations remontent encore en log, elles sont traitées une par une par les prochaines corrections Rector à planifier.

Valider que la qualimetry est toujours stable

make qualimetry

En plus de l’outils Rector qui accélère cette phase de mise à jour, nous avons développer le smartbooster/standard-bundle qui via des analyses statiques (en plus des checkstyles) va venir confirmer que ces modifications n’ont pas introduit d’autre erreur qui ne serait pas remonté par les tests.

Vérifier les logs applicatifs

Après le déploiement sur la recette, nous consultons les logs Sentry/Monolog pour une vérification complémentaire sur environnement.

À ce stade aucune Deprecated PHP ne devrait remonter sur Sentry ou autre erreur PHP.

Déployer en production via GitLab CI/CD

Chez SmartBooster, nous utilisons le déploiement continu GitLab pour pousser les changements en production. Une fois la branche de migration validée sur la recette, la mise en production est lancée directement depuis l’interface GitLab : le pipeline se charge du déploiement sur Clever Cloud avec la variable CC_PHP_VERSION=8.4 déjà configurée (étape 4), sans intervention manuelle sur le serveur.

Le déploiement et les métriques sont surveillés pendant la première heure, avec Sentry toujours actif pour remonter le moindre problème en production.

Conclusion

Migrer de PHP 8.3 à 8.4 est une migration de maintenance préventive, pas un chantier de refactoring. Avec Rector, la correction des dépréciations est largement automatisée et prend rarement plus d’une demi-journée sur un projet bien testé.

La clé du succès : traiter les dépréciations à zéro avant de pousser en production. Un projet sans messages Deprecated dans les logs est un projet sain, performant et agréable à maintenir.


Liens utiles

Mathieu Ducrot
Mathieu Ducrot CTO
Mots clés :
#Qualité #Productivité

Articles similaires

Vous avez un projet ?

Contactez-nous pour savoir comment nous pouvons vous aider.