# La classe Collator de PHP trie une liste de termes selon chaque langue

> usort avec strcmp compare des octets, pas des lettres : la classe Collator de l'extension intl trie enfin une liste de termes selon les règles de chaque langue.

- Auteur : WordPress Développement
- Publié le : 2023-07-29
- Mis à jour le : 2023-07-29
- Catégorie : Multilingue
- URL : https://www.wpmoderne.fr/multilingue/classe-collator-php-trier-termes-traduits/

## L’essentiel

- strcmp compare des octets UTF-8 bruts, jamais des règles linguistiques
- Collator applique les règles de tri Unicode d'une locale
- getSortKey produit une clé réutilisable pour trier de grandes listes

`usort( $termes, 'strcmp' )` : cette ligne, d'apparence anodine, classe « Étude » après « Zoologie » dans une liste de termes de taxonomie affichée en français. Le problème ne vient ni de WordPress ni de la base de données : `strcmp()` compare des octets UTF-8 bruts, sans la moindre notion de langue, et le caractère « É », encodé sur plusieurs octets, se retrouve mécaniquement classé après le « Z » d'un seul octet.

Ce billet porte sur le tri effectué côté PHP, une fois la liste de termes déjà récupérée en mémoire, avec la classe `Collator` de l'extension `intl`. Il ne traite pas du choix de la collation MySQL ni de la conversion d'une base vers `utf8mb4`, deux sujets traités séparément et propres au stockage plutôt qu'au tri applicatif.

## Pourquoi strcmp ne convient jamais à un tri lisible pour un humain

`strcmp()`, utilisée par défaut dans un `usort()` naïf sur un tableau de chaînes, compare deux chaînes octet par octet, dans l'ordre de leur représentation binaire en UTF-8. Ce comportement, parfaitement correct pour un tri strictement binaire ou une comparaison d'égalité, produit un ordre incohérent pour un lecteur humain dès qu'un caractère accentué, cyrillique ou tout autre caractère hors de l'ASCII pur entre dans la comparaison :

```
$termes = array( 'Étude', 'Zoologie', 'Architecture' );
usort( $termes, 'strcmp' );
// Résultat possible : Architecture, Zoologie, Étude
// « É », multi-octets en UTF-8, se classe après « Z » en comparaison d'octets bruts
```

## Instancier un Collator pour une locale précise

L'extension `intl` de PHP, généralement disponible sur les hébergements récents, fournit la classe `Collator`, qui applique les règles de tri Unicode propres à une locale donnée plutôt qu'une simple comparaison d'octets. Sa méthode `sort()` réordonne directement un tableau de chaînes :

```
$collator = new Collator( 'fr_FR' );
$termes   = array( 'Étude', 'Zoologie', 'Architecture' );
$collator->sort( $termes );
// Résultat : Architecture, Étude, Zoologie
```

> L'essentiel à retenir : strcmp compare des octets UTF-8 bruts, jamais des règles linguistiques ; Collator applique les règles de tri Unicode d'une locale ; getSortKey produit une clé réutilisable pour trier de grandes listes

## Trier une liste de termes WordPress avec Collator

Appliqué à une liste de termes récupérée via `get_terms()`, le tri se fait sur la propriété `name` de chaque objet `WP_Term`, en s'appuyant sur `usort()` combiné à la méthode `compare()` du Collator, qui retourne un entier négatif, nul ou positif comme `strcmp()`, mais en respectant les règles linguistiques de la locale choisie :

```
$collator = new Collator( get_locale() );
$termes   = get_terms( array( 'taxonomy' => 'sujet', 'hide_empty' => false ) );

usort( $termes, function ( $terme_a, $terme_b ) use ( $collator ) {
    return $collator->compare( $terme_a->name, $terme_b->name );
} );
```

Utiliser `get_locale()` plutôt qu'une locale codée en dur garantit que le tri suit la langue réellement active au moment de l'affichage, sur un site multilingue où plusieurs locales peuvent se succéder au fil des requêtes.

## getSortKey : accélérer le tri d'une grande liste

Pour une liste de plusieurs milliers de termes, appeler `compare()` à chaque comparaison d'un algorithme de tri recalcule les règles de collation à chaque paire comparée. La méthode `getSortKey()` précalcule, pour chaque chaîne, une clé de tri stable, qui peut ensuite être comparée avec un simple `strcmp()`, bien plus rapide sur un grand volume :

```
$collator = new Collator( 'fr_FR' );

$paires = array_map( function ( $terme ) use ( $collator ) {
    return array( 'cle' => $collator->getSortKey( $terme->name ), 'terme' => $terme );
}, $termes );

usort( $paires, function ( $a, $b ) {
    return strcmp( $a['cle'], $b['cle'] );
} );

$termes = array_column( $paires, 'terme' );
```

## Ce que Collator ne résout pas entièrement

- Le russe et la plupart des alphabets cyrilliques bénéficient d'un tri correct avec la locale adaptée, mais certains caractères empruntés à d'autres alphabets slaves restent des cas limites.
- Les kanjis japonais ne possèdent aucun ordre alphabétique intrinsèque : leur tri conventionnel se fait par lecture phonétique ou par nombre de traits, une information que `Collator` ne déduit pas seul du caractère.
- La disponibilité de l'extension `intl` doit être vérifiée avec `extension_loaded( 'intl' )` avant tout usage, certains hébergements mutualisés ne l'activant pas par défaut.

> Un tri qui doit rester lisible pour un humain ne se fait jamais avec une comparaison d'octets bruts : Collator coûte un peu de mise en place, mais reste la seule voie fiable disponible nativement en PHP.

## En résumé

Trier une liste de termes récupérée depuis WordPress avec `strcmp()` classe les caractères accentués ou non latins n'importe où dans le résultat, sans respecter aucune convention linguistique. La classe `Collator` de l'extension `intl`, instanciée avec la locale active du site, corrige ce défaut pour la plupart des écritures, et sa méthode `getSortKey()` permet de garder ce tri rapide même sur une liste de plusieurs milliers de termes.
