# Des résultats inattendus dans un tri de gabarits, faute d’un === en PHP

> Un gabarit toujours relégué en fin de liste, alors que son ordre déclaré le plaçait en premier : la cause tenait à une comparaison PHP trop permissive, pas au tri lui-même.

- Auteur : WordPress Développement
- Publié le : 2024-08-19
- Mis à jour le : 2024-08-19
- Catégorie : Éditeur de site (FSE)
- URL : https://www.wpmoderne.fr/fse/resultats-inattendus-tri-gabarits-faute-triple-egal/

## L’essentiel

- array_search peut renvoyer 0, une valeur parfaitement valide mais faussement falsy
- Une condition if sur ce retour doit toujours vérifier !== false
- Le bug ne se manifeste que pour le premier élément d'une liste, ce qui retarde sa découverte

« Le gabarit d'accueil personnalisé s'affiche toujours en dernier dans le sélecteur, jamais en premier comme prévu » : ce signalement, remonté par une cliente qui gérait elle-même l'ordre d'affichage de plusieurs gabarits personnalisés dans un menu déroulant du thème, a mis plusieurs jours à être reproduit de façon fiable, avant qu'un test isolé ne révèle un comportement systématique lié à un seul indice précis.

## Symptôme : un ordre correct pour tous, sauf un

Le thème proposait un tableau `$ordre_gabarits`, déclaré dans `functions.php`, qui fixait l'ordre d'affichage souhaité des gabarits personnalisés dans un menu de navigation secondaire. Chaque gabarit devait apparaître à la position définie par cet ordre, sauf celui placé explicitement en première position, qui se retrouvait systématiquement relégué en toute fin de liste, quel que soit le contenu réel du tableau.

## Diagnostic : un retour de fonction confondu avec un booléen

> L'essentiel à retenir : array_search peut renvoyer 0, une valeur parfaitement valide mais faussement falsy ; Une condition if sur ce retour doit toujours vérifier !== false ; Le bug ne se manifeste que pour le premier élément d'une liste, ce qui retarde sa découverte

Le code responsable du tri s'appuyait sur `array_search()` pour retrouver la position déclarée d'un gabarit, avant de l'utiliser comme clé de tri :

```
foreach ( $gabarits as $gabarit ) {
    $position = array_search( $gabarit->slug, $ordre_gabarits );

    if ( $position ) {
        $gabarit->ordre = $position;
    } else {
        $gabarit->ordre = 999;
    }
}
```

`array_search()` renvoie l'indice de l'élément trouvé dans le tableau, ou `false` si l'élément est absent. Pour le premier élément du tableau `$ordre_gabarits`, cet indice vaut `0` — une valeur entière parfaitement valide, mais que PHP considère comme fausse dans un contexte booléen, exactement comme `false` lui-même. La condition `if ( $position )` traitait donc ce cas comme un échec de recherche, et affectait au gabarit concerné l'ordre par défaut réservé aux éléments non trouvés.

## Correctif : une comparaison stricte au type

Le correctif consiste à remplacer la comparaison implicite par une comparaison stricte, explicitement au type, pour distinguer `0` (une position valide) de `false` (une absence réelle) :

```
foreach ( $gabarits as $gabarit ) {
    $position = array_search( $gabarit->slug, $ordre_gabarits );

    if ( $position !== false ) {
        $gabarit->ordre = $position;
    } else {
        $gabarit->ordre = 999;
    }
}
```

Après ce changement, le gabarit d'indice 0 dans `$ordre_gabarits` retrouvait sa position réelle, et le tri final produisait l'ordre attendu pour l'ensemble des gabarits, sans exception.

## Pourquoi ce bug est resté invisible aussi longtemps

La condition fautive fonctionnait correctement pour tous les indices supérieurs à zéro, qui restent évalués comme vrais dans un contexte booléen. Seul l'élément placé en première position du tableau déclenchait le comportement incorrect, ce qui explique pourquoi les tests menés en modifiant l'ordre des autres gabarits ne révélaient jamais le problème : il fallait spécifiquement placer un gabarit en tout premier pour l'observer.

## Prévention pour la suite

- traiter systématiquement le retour de `array_search()`, `strpos()` ou `array_key_first()` avec une comparaison stricte au type, jamais avec une simple condition implicite ;
- ajouter un test unitaire dédié qui place explicitement un élément en position 0, précisément parce que ce cas limite échappe facilement à une relecture rapide du code ;
- activer un niveau d'analyse statique du code qui signale les comparaisons implicites sur des fonctions dont le retour peut valoir zéro ou une chaîne vide en cas de succès.

> Nous relisons systématiquement tout usage de `array_search()`, `strpos()` ou `array_search()` dans une revue de code, en cherchant explicitement l'absence d'un `!== false` : c'est l'un des rares réflexes de relecture qui a un rapport temps investi contre bugs évités aussi favorable.

## Ce qu'il faut retenir

Ce bug n'avait rien d'exotique : il s'agit d'une des confusions les plus documentées du langage PHP, entre une valeur falsy légitime et une absence de résultat. Sa discrétion tenait uniquement au fait qu'il ne se manifestait que pour un seul indice précis d'un tableau, ce qui l'a rendu difficile à isoler tant que personne n'avait pensé à tester spécifiquement ce cas limite.
