vendredi 25 septembre 2026

À propos

Contact

Extensions

Retour d’expérience : migrer une extension WordPress client vers PHP 8

Types nullable, changements de comportement sur les chaînes, dépréciations : ce qu'on a vraiment rencontré en migrant une extension métier de dix mille lignes vers PHP 8.

Par Clément Hadrot • 18 janvier 2022 • 5 min de lecture • Aucun commentaire
Retour d'expérience : migrer une extension WordPress client vers PHP 8

Fin 2020, WordPress 5.6 a officiellement ajouté la prise en charge de PHP 8, sorti la même année. Un an plus tard, plusieurs hébergeurs mutualisés proposaient PHP 8.0 par défaut sur les nouvelles installations, et nos clients ont commencé à nous demander de vérifier la compatibilité de leurs extensions métier maison. Ce retour d’expérience porte sur la migration d’une extension de gestion de commandes B2B, environ dix mille lignes de code PHP écrites entre 2016 et 2019, jamais pensée pour PHP 8 à l’origine.

Contrairement à ce que la peur ambiante autour des « breaking changes » de PHP 8 pouvait laisser penser, la migration s’est révélée rapide : trois jours de travail effectif, tests inclus, pour une extension de cette taille. Voici les points qui ont réellement posé problème, et ceux qui, malgré leur réputation, n’ont causé aucun souci.

Ce qui a effectivement cassé

Les fonctions de chaînes avec un argument null

PHP 8.1 (sorti fin novembre 2021, donc encore récent au moment de cette migration) a commencé à déprécier le passage de null aux paramètres non nullables de nombreuses fonctions internes comme strlen(), trim() ou str_replace(). Sous PHP 8.0, ce comportement était encore silencieusement toléré mais déjà signalé par un avertissement en environnement de développement avec WP_DEBUG actif.

// Cassait avec un avertissement de dépréciation sous PHP 8.1
$reference = trim( $commande->reference ); // reference peut être null en base

// Correction systématique
$reference = trim( (string) $commande->reference );
// ou, plus lisible :
$reference = trim( $commande->reference ?? '' );

Ce fut, de loin, le correctif le plus fréquent : une quarantaine d’occurrences dans le code, principalement autour des champs de métadonnées facultatifs récupérés via get_post_meta(), qui retourne une chaîne vide et non null, mais dont certaines valeurs héritées de l’ancienne version de l’extension étaient réellement null en base pour des enregistrements anciens.

Un tri de tableau devenu stable

PHP 8.0 a rendu le tri des tableaux stable par défaut (deux éléments de même valeur conservent leur ordre relatif d’origine). Un comportement globalement positif, mais qui a changé l’ordre d’affichage d’une liste de produits triée par une fonction de comparaison personnalisée avec usort(), où l’ancien tri instable masquait involontairement un bug de comparaison préexistant. La correction a consisté à revoir la fonction de comparaison elle-même plutôt qu’à contourner le nouveau comportement.

L'essentiel à retenir : str_contains évite des bidouillages avec strpos ; Les arguments nommés cassent parfois les hooks à callback dynamique ; match remplace avantageusement de nombreux switch

Ce qui n’a, en pratique, posé aucun problème

Contrairement aux craintes initiales, plusieurs changements réputés « cassants » de PHP 8 n’ont eu aucun impact sur cette extension :

  • Les erreurs de type TypeError sur les arguments internes mal typés : le code, bien que non typé explicitement, passait déjà des types cohérents dans l’immense majorité des cas.
  • La suppression de certaines fonctions dépréciées depuis longtemps (create_function(), each()) : absentes du code car déjà signalées par les linters utilisés en amont.
  • Les changements de tri par clé dans certaines fonctions de tableau : l’extension ne dépendait d’aucun ordre implicite non documenté à cet endroit.

Ce qui a été amélioré, pas juste corrigé

La migration a aussi été l’occasion d’adopter des fonctionnalités PHP 8 qui simplifient réellement le code existant.

// Avant : recherche de sous-chaîne verbeuse
if ( strpos( $statut, 'annule' ) !== false ) { /* ... */ }

// Après PHP 8 : lisibilité immédiate, plus d'erreur classique sur le === false
if ( str_contains( $statut, 'annule' ) ) { /* ... */ }
// Avant : un switch de huit cas
switch ( $type_commande ) {
    case 'standard':
        $delai = 3;
        break;
    case 'express':
        $delai = 1;
        break;
    default:
        $delai = 5;
}

// Après PHP 8 : match, plus concis, sans fall-through possible
$delai = match ( $type_commande ) {
    'standard' => 3,
    'express'  => 1,
    default    => 5,
};

match présente un avantage de sécurité par rapport à switch : la comparaison est stricte (équivalent à ===) et l’absence de break élimine tout risque d’oubli provoquant un fall-through silencieux vers le cas suivant, une classe de bug qui avait déjà causé un incident en production sur cette même extension, des années plus tôt.

Le vrai piège : les callbacks dynamiques et les arguments nommés

Un point plus subtil a nécessité une vérification manuelle attentive : les hooks WordPress qui appellent un callback avec des arguments positionnels stricts. PHP 8 introduit les arguments nommés (ma_fonction( id: 42, statut: 'actif' )), une fonctionnalité que l’extension n’utilisait pas mais qui aurait pu entrer en conflit avec des callbacks dont les noms de paramètres ne correspondaient pas exactement à ceux attendus par des filtres tiers, si une future évolution du code avait adopté cette syntaxe sans vérification. Ce risque, bien que non concrétisé sur cette migration, a été documenté pour l’équipe.

Notre conclusion après cette migration, et plusieurs autres menées depuis sur des extensions similaires : la peur de PHP 8 est largement disproportionnée par rapport au risque réel, à condition que le code ait déjà respecté des pratiques raisonnables de typage implicite. Le vrai travail se situe dans les zones où les données en base sont plus permissives que ce que le code suppose.

La méthode de test qui a limité les mauvaises surprises

  • Activer WP_DEBUG et WP_DEBUG_LOG sur un environnement de recette sous PHP 8.0, et parcourir manuellement chaque écran de l’extension en observant le fichier de log
  • Lancer la suite de tests existante (PHPUnit) sous PHP 8.0 avant toute correction, pour établir une base de référence des échecs
  • Utiliser wp plugin verify-checksums et un simple php -l sur chaque fichier pour écarter d’emblée les erreurs de syntaxe grossières

En résumé

La migration d’une extension métier vers PHP 8 s’est révélée moins coûteuse que redouté, à condition de traiter sérieusement le sujet des valeurs null transmises à des fonctions de chaînes. Les nouveautés du langage — match, str_contains(), la coercition explicite des types — ont, en prime, permis de simplifier une partie du code existant à l’occasion de cette mise à niveau.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi