# Passer ses tests PHPUnit à PHP 8 avec l’arrivée de WordPress 5.6

> WordPress 5.6 annonce la compatibilité PHP 8. Retour d'expérience sur les erreurs de typage et les dépréciations qui ont cassé nos suites PHPUnit lors de la migration.

- Auteur : Clément Hadrot
- Publié le : 2021-01-13
- Mis à jour le : 2021-01-13
- Catégorie : Tests
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tests/migrer-tests-php8-wordpress-56/

## L’essentiel

- Le typage strict de PHP 8 révèle des bugs silencieux depuis des années
- Une matrice CI à étendre avant de généraliser PHP 8
- Des fonctions dépréciées à traquer avant qu'elles ne cassent en prod

WordPress 5.6, sorti en décembre dernier, annonce officiellement la compatibilité avec PHP 8. C'est une bonne nouvelle pour l'écosystème, mais aussi le signal qu'il est temps de vérifier sérieusement que nos plugins et thèmes tiennent la route sur cette nouvelle version majeure de PHP. Nous avons passé les tests PHPUnit de plusieurs projets clients sous PHP 8 ces dernières semaines, et le bilan mérite d'être partagé : rien de catastrophique, mais suffisamment de surprises pour justifier un vrai travail de migration avant de généraliser.

Cet article revient sur les erreurs les plus fréquentes rencontrées, la façon d'adapter la configuration de test, et la stratégie de matrice de CI que nous avons mise en place pour sécuriser la transition sans tout casser du jour au lendemain.

## Ce que PHP 8 change concrètement pour vos tests

PHP 8 introduit un typage plus strict sur plusieurs points qui, auparavant, se contentaient d'un avertissement silencieux. Le changement le plus visible dans nos suites de tests concerne les arguments manquants ou de type incorrect passés à des fonctions internes : ce qui produisait un `Warning` ignoré en PHP 7 devient une `TypeError` qui interrompt franchement l'exécution, et donc fait échouer le test PHPUnit correspondant.

Deux autres nouveautés de PHP 8 ont un effet direct sur le code de nos plugins : l'ajout des fonctions natives `str_contains()`, `str_starts_with()` et `str_ends_with()`, qui remplacent avantageusement des usages fragiles de `strpos()`, et la possibilité d'utiliser des arguments nommés dans les appels de fonction, ce qui peut révéler des incohérences dans l'ordre des paramètres de fonctions maison peu documentées.

## Adapter phpunit.xml.dist et la matrice de CI

Avant de tester quoi que ce soit sous PHP 8, il faut s'assurer que PHPUnit lui-même est compatible. Les versions de PHPUnit antérieures à la 8.5 ne fonctionnent pas correctement sous PHP 8 : nous recommandons de monter au minimum vers PHPUnit 9.x sur les projets qui visent PHP 8, tout en gardant PHPUnit 7 ou 8 sur les branches qui doivent encore supporter PHP 7.2.

```
composer require --dev phpunit/phpunit:^9.0
```

Sur notre configuration GitHub Actions, nous avons étendu la matrice existante pour ajouter PHP 8.0 en plus des versions déjà couvertes, sans retirer PHP 7.4 qui reste la version la plus déployée chez nos hébergeurs :

```
strategy:
  matrix:
    php: ['7.4', '8.0']
    wordpress: ['5.6']
```

> L'essentiel à retenir : Le typage strict de PHP 8 révèle des bugs silencieux depuis des années ; Une matrice CI à étendre avant de généraliser PHP 8 ; Des fonctions dépréciées à traquer avant qu'elles ne cassent en prod

## Les erreurs les plus fréquentes rencontrées

### Arguments implicitement nullables

PHP 8 déprécie la déclaration implicite d'un paramètre typé comme nullable simplement parce que sa valeur par défaut est `null`. Ce code, courant dans d'anciens plugins, génère désormais un avertissement de dépréciation qui peut faire échouer un test strict sur les erreurs PHP :

```
// Avant : comportement à corriger, déjà signalé en dépréciation dès PHP 8.0
function mon_plugin_formate( string $texte = null ) {
    return $texte ? trim( $texte ) : '';
}

// Après : type explicitement nullable
function mon_plugin_formate( ?string $texte = null ) {
    return $texte ? trim( $texte ) : '';
}
```

### Tri de tableaux et fonctions internes

Certaines fonctions de tri, comme `usort()`, deviennent stables en PHP 8 : deux éléments considérés comme égaux par la fonction de comparaison conservent leur ordre d'origine. Nos tests qui vérifiaient un ordre précis sur des éléments à égalité, sans s'appuyer sur cette stabilité, ont dû être ajustés pour ne plus dépendre d'un comportement non garanti sous PHP 7.

### Concaténation et opérateurs

La précédence de l'opérateur de concaténation `.` change légèrement par rapport aux opérateurs arithmétiques en PHP 8. Un code du type `'Total : ' . $a + $b`, qui fonctionnait par accident, produit désormais une erreur de type au lieu du résultat attendu. Ce genre de code, rare mais pas inexistant dans des templates anciens, vaut la peine d'être recherché avec un grep ciblé avant la migration.

## Utiliser PHPUnit pour sécuriser la transition

Plutôt que de migrer un plugin entier d'un coup, nous avons ajouté des tests ciblés sur les fonctions les plus sensibles au typage avant de changer quoi que ce soit dans le code applicatif. Ce test, par exemple, garantit qu'une fonction accepte toujours une valeur nulle sans lever d'erreur :

```
class Test_Formatage_Texte extends WP_UnitTestCase {

    public function test_accepte_une_valeur_nulle() {
        $this->assertSame( '', mon_plugin_formate( null ) );
    }

    public function test_retire_les_espaces_superflus() {
        $this->assertSame( 'bonjour', mon_plugin_formate( '  bonjour  ' ) );
    }
}
```

Ce test passe sous PHP 7.4 comme sous PHP 8.0 une fois la signature corrigée, ce qui donne une garantie de non-régression pendant tout le reste de la migration.

## Une checklist avant de généraliser PHP 8

- Vérifier la version minimale de PHPUnit compatible et l'aligner dans `composer.json`.
- Étendre la matrice CI pour couvrir PHP 8.0 sans retirer les versions encore en production chez vos clients.
- Chercher les paramètres typés avec une valeur par défaut `null` non déclarée nullable.
- Repasser en revue les fonctions de tri qui supposaient un ordre instable.
- Activer `error_reporting( E_ALL )` dans l'environnement de test pour faire remonter les dépréciations plutôt que de les laisser silencieuses.

> Sur nos projets, nous ne basculons jamais un client en production sur PHP 8 avant que sa suite PHPUnit ne tourne intégralement, sans avertissement, sur les deux versions de PHP en parallèle dans la CI. C'est la seule façon d'avoir confiance dans la bascule finale.

## En résumé

La compatibilité PHP 8 annoncée par WordPress 5.6 ne se limite pas à une case à cocher : elle impose de repasser en revue le typage, l'ordre des paramètres et certains comportements de fonctions internes qui changent discrètement. Une suite PHPUnit existante, étendue à une matrice de versions PHP en CI, est l'outil le plus fiable pour sécuriser cette transition avant de généraliser PHP 8 sur des projets clients en production.
