Le WordPress d'aujourd'hui, décodé pour les développeurs

Tests

PHP 8.3 : les dépréciations qui font échouer silencieusement PHPUnit

Sans configuration stricte, PHPUnit avale des avertissements de dépréciation PHP 8.3 qui devraient faire échouer la suite. Voici comment les rendre visibles.

Par WordPress Développement • 29 décembre 2023 • 4 min de lecture • Aucun commentaire
PHP 8.3 : les dépréciations qui font échouer silencieusement PHPUnit

« Deprecated: Implicit conversion from float-string to int is deprecated » — ce message traîne dans les logs de production depuis la mise à jour vers PHP 8.3, mais la suite PHPUnit du projet reste verte, ligne après ligne. C’est le signe d’un problème plus profond que le message lui-même : la configuration des tests n’écoute pas ce que PHP a pourtant crié.

PHP 8.3 a ajouté de nouvelles dépréciations, notamment autour des méthodes magiques dynamiques et des propriétés non déclarées explicitement dans certaines classes. Par défaut, ces avertissements ne stoppent rien : ils s’affichent, ou pas, et l’exécution continue comme si de rien n’était.

Comprendre pourquoi PHPUnit reste silencieux

PHPUnit ne convertit les erreurs PHP en échecs de test que si on le lui demande explicitement. Sans configuration, un E_DEPRECATED est simplement journalisé selon la valeur de error_reporting, puis ignoré par le framework de test. Le test passe, le comportement problématique reste invisible jusqu’à ce qu’il devienne une vraie erreur dans une version PHP ultérieure.

Le fichier phpunit.xml du projet contenait encore convertDeprecationsToExceptions="false", un réglage hérité d’une époque où le bruit des dépréciations WordPress rendait la suite illisible. Ce choix, raisonnable en 2020, était devenu une faille de couverture en 2023.

Rendre les dépréciations visibles sans casser la suite entière

L'essentiel à retenir : E_DEPRECATED n'arrête pas un test par défaut ; error_reporting mal configuré masque le signal ; Un handler dédié transforme l'avertissement en échec

La solution brutale — activer convertDeprecationsToExceptions="true" partout — a fait exploser 340 échecs d’un coup, la plupart venant du cœur WordPress lui-même et hors de portée du projet. Il fallait un filtre plus fin.

set_error_handler(function ($errno, $errstr, $errfile) {
    if ($errno === E_DEPRECATED && strpos($errfile, '/wp-content/plugins/mon-plugin/') !== false) {
        throw new \PHPUnit\Framework\Error\Deprecated($errstr, $errno, $errfile);
    }
    return false;
}, E_DEPRECATED);

Ce handler personnalisé, chargé dans le bootstrap des tests, ne transforme en échec que les dépréciations émises par le code du plugin lui-même. Le bruit du cœur WordPress continue d’être journalisé, sans polluer le résultat de la suite.

Cibler les fonctions réellement concernées par PHP 8.3

Trois cas ont émergé de cette chasse : un cast implicite de chaîne numérique en entier dans une boucle de pagination, une comparaison utilisant == sur un objet DateTime là où === était attendu, et l’accès à une propriété dynamique non déclarée sur une classe sans #[AllowDynamicProperties].

  • Cast implicite float-string vers int dans un compteur de pages
  • Propriété dynamique non déclarée sur une classe de service interne
  • Appel d’une méthode magique __get sur un attribut absent

Adapter la CI plutôt que la machine locale

Un développeur travaillant en local sous PHP 8.1 ne verrait jamais ces messages. La CI a donc été configurée pour exécuter systématiquement un job dédié sous PHP 8.3, avec le handler strict activé, séparé du job principal qui reste tolérant pour ne pas bloquer les contributions en cours.

Ce job supplémentaire ajoute environ deux minutes par exécution, mais il a permis de corriger les trois cas cités avant qu’ils ne deviennent des erreurs fatales lors d’une future montée de version PHP.

Un avertissement PHP qui ne fait échouer aucun test n’est pas résolu, il est juste reporté à plus tard — souvent au pire moment.

Vérifier que la prévention tient dans le temps

Pour éviter que ce filtre ne devienne lui-même un point mort, un test unitaire vérifie que le handler personnalisé est bien enregistré au démarrage de la suite, et qu’il transforme effectivement un E_DEPRECATED simulé en exception. Sans ce garde-fou, une future réécriture du bootstrap pourrait supprimer silencieusement la protection.

En résumé

Le réglage par défaut de PHPUnit sur les dépréciations privilégie le confort immédiat au détriment de la détection précoce. Un handler ciblé, limité au code du projet, a permis de retrouver un signal exploitable sans revenir au bruit généralisé d’une conversion totale en exceptions. La leçon tient en une phrase : une suite verte n’est une bonne nouvelle que si elle écoute vraiment tout ce que PHP lui dit.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

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

Voir tous ses articles

Dans la même veine

À lire aussi