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

Thèmes

PHP 8.3 et un thème hérité : des classes readonly qui cassent des widgets

L'effet des classes readonly de PHP 8.3 sur une ancienne bibliothèque de widgets d'un thème vieux de plusieurs années, et comment y remédier sans tout réécrire.

Par WordPress Développement • 11 février 2024 • 5 min de lecture • Aucun commentaire
PHP 8.3 et un thème hérité : des classes readonly qui cassent des widgets

PHP 8.3, sorti en novembre 2023, ne fait qu’affiner un mécanisme déjà introduit par les deux versions précédentes : les propriétés readonly individuelles datent de PHP 8.1, et la possibilité de déclarer une classe entière comme readonly — appliquant automatiquement la contrainte à toutes ses propriétés — remonte à PHP 8.2. Sur un serveur qui saute directement de PHP 7.4 à PHP 8.3, ces deux changements arrivent d’un coup, et c’est souvent la version la plus récente qui reçoit, à tort, tout le blâme.

C’est exactement ce qui s’est produit sur un thème vieux de plusieurs années, qui embarquait une bibliothèque tierce de gestion de widgets jamais mise à jour depuis sa livraison initiale. La montée de version PHP du serveur d’hébergement, passée directement de 7.4 à 8.3, a suffi à faire apparaître des erreurs jusque-là invisibles.

Symptôme : des widgets qui refusent silencieusement de s’enregistrer

Après la mise à jour de PHP sur le serveur d’hébergement mutualisé, plusieurs widgets de la bibliothèque tierce ont cessé de s’afficher dans l’administration, sans message d’erreur visible côté front, mais avec des entrées explicites dans le journal d’erreurs PHP du serveur.

PHP Fatal error: Uncaught Error: Cannot modify readonly property Widget_Config::$options in /wp-content/themes/theme-heritage/lib/widgets/class-widget-config.php on line 42
L'essentiel à retenir : readonly n'existait qu'au niveau propriété avant PHP 8.3 ; La bibliothèque de widgets modifiait des propriétés censées rester figées ; Correction ciblée sans réécrire toute la bibliothèque

Diagnostic : une classe déclarée readonly, une propriété modifiée après coup

En inspectant la bibliothèque tierce, la classe Widget_Config avait été déclarée readonly par son auteur — vraisemblablement lors d’une mise à jour pensée pour PHP 8.2, jamais testée sur une version de PHP aussi ancienne que celle encore utilisée par ce thème — sans anticiper que du code appelant modifierait une de ses propriétés après l’instanciation initiale. Un pattern courant dans des bibliothèques anciennes qui construisent un objet en plusieurs étapes plutôt qu’en un seul appel de constructeur.

final readonly class Widget_Config {
    public array $options;

    public function __construct( array $options ) {
        $this->options = $options;
    }
}

// Plus loin dans le code du thème :
$config = new Widget_Config( array() );
$config->options = array_merge( $config->options, $reglages_supplementaires ); // Échoue sur PHP 8.3

Correctif : reconstruire l’objet plutôt que le modifier

Puisque la bibliothèque tierce n’était plus maintenue, réécrire toute sa logique interne n’était pas envisageable dans les délais impartis. La correction retenue consiste à ne plus jamais modifier une propriété d’un objet readonly après sa création, mais à instancier un nouvel objet avec les valeurs déjà fusionnées.

$config = new Widget_Config(
    array_merge(
        ( new Widget_Config( array() ) )->options,
        $reglages_supplementaires
    )
);

Cette réécriture ponctuelle, limitée aux quelques points d’appel qui modifiaient effectivement une propriété après coup, a suffi à rétablir le fonctionnement des widgets sans toucher au code source de la bibliothèque tierce elle-même.

Identifier tous les points d’appel concernés

Une simple recherche du nom de la propriété dans l’ensemble du thème, combinée à une relecture manuelle de chaque résultat pour distinguer une lecture d’une écriture, a permis de recenser six points d’appel problématiques sur l’ensemble du thème, tous corrigés selon le même principe de reconstruction d’objet.

  • Recherche textuelle du nom de chaque propriété de la classe concernée dans tout le thème.
  • Vérification manuelle de chaque occurrence : lecture simple ou tentative de modification après instanciation.
  • Test de chaque widget concerné en environnement de préproduction avant validation du correctif en production.

La prévention pour la suite

Ce thème hérité n’ayant plus de mainteneur côté bibliothèque tierce, la vigilance porte désormais sur chaque montée de version PHP planifiée par l’hébergeur : un environnement de test avec la version cible de PHP est systématiquement mis en place quelques semaines avant tout changement, pour repérer ce type d’incompatibilité avant qu’elle n’atteigne la production.

Une classe déclarée readonly par un tiers n’est pas un simple détail syntaxique : c’est un contrat qui interdit toute modification ultérieure. Sur du code hérité qui n’anticipait pas cette contrainte, la seule solution propre reste de reconstruire l’objet plutôt que de contourner la protection.

En résumé

Les classes entièrement readonly, introduites par PHP 8.2 et renforçant une garantie déjà présente depuis PHP 8.1 au niveau des propriétés individuelles, peuvent faire ressurgir des habitudes de code héritées qui reposaient sur la mutabilité d’un objet après sa création. Sur un thème ancien qui embarque des bibliothèques tierces non maintenues, chaque montée de version PHP — surtout lorsqu’elle saute plusieurs versions d’un coup, comme ici jusqu’à PHP 8.3 — mérite un passage systématique en environnement de test avant toute mise à jour du serveur de production.

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