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
- Vérifier la compatibilité de vos extensions PHP
- Corriger les changements de comportement avec Rector
- Mettre à jour vos dépendances Composer
- Mettre à jour vos environnements
- Mettre à jour PHPUnit en parallèle
- Documenter la migration dans le
maintenance.md - 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_STRICTsupprimé : la constante existe toujours mais n’est plus levée.exit()/die()deviennent des vraies fonctions : ils peuvent maintenant être passés comme callbacks.GMPinteger 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
- Migration officielle PHP 8.4 : Le guide de référence PHP, dépréciations et BC breaks
- PHP.Watch - PHP 8.4 changelog Autre source de suivi détaillé des changements avec exemples
- Rector - Documentation officielle
- Rector - Set Lists disponibles : Liste complète des sets préconfigurés