« niveau_permission » égale « editeur_junior » dans une base de données, et « editeur_junoir » dans le code qui vérifie cette valeur quelques lignes plus loin : ce genre de faute de frappe, invisible tant que personne ne teste précisément ce niveau de permission, illustre la fragilité d’une hiérarchie personnalisée modélisée uniquement par des chaînes de caractères libres.
Le contexte : une hiérarchie de permissions au-delà des rôles WordPress
Les rôles et capacités natifs de WordPress couvrent une grande partie des besoins courants, mais une application métier construite sur WordPress introduit parfois une hiérarchie de permissions plus fine que celle exposée par current_user_can(), par exemple pour distinguer plusieurs niveaux d’accès à un espace de documents internes, indépendamment du rôle WordPress de l’utilisateur. Cette hiérarchie interne est souvent modélisée par une simple chaîne stockée en métadonnée utilisateur.
Le problème d’une chaîne de caractères libre
function verifier_acces(string $niveau_permission, string $document): bool
{
return match ($niveau_permission) {
'lecture_seule' => est_document_public($document),
'editeur_junior' => est_document_public($document) || est_document_equipe($document),
'editeur_senior' => true,
default => false,
};
}
Rien n’empêche, ailleurs dans le code, d’écrire ou de stocker une valeur légèrement différente : 'Editeur_Junior' avec une majuscule, ou 'editeur-junior' avec un trait d’union. Ces variantes tombent silencieusement dans la branche default, refusant l’accès sans qu’aucune erreur ne signale la cause réelle du problème, à savoir une incohérence de nommage plutôt qu’un véritable refus de permission.

La modélisation avec un enum backé
PHP 8.1 introduit les enums, y compris une variante backée par une valeur scalaire, qui restreint les valeurs possibles d’un type à un ensemble fermé et connu au moment de l’écriture du code :
enum NiveauPermission: string
{
case LectureSeule = 'lecture_seule';
case EditeurJunior = 'editeur_junior';
case EditeurSenior = 'editeur_senior';
public static function depuisChaine(string $valeur): self
{
return self::from($valeur);
}
}
function verifier_acces(NiveauPermission $niveau, string $document): bool
{
return match ($niveau) {
NiveauPermission::LectureSeule => est_document_public($document),
NiveauPermission::EditeurJunior => est_document_public($document) || est_document_equipe($document),
NiveauPermission::EditeurSenior => true,
};
}
La méthode statique NiveauPermission::from(), fournie nativement par les enums backés, lève une erreur ValueError si la chaîne fournie ne correspond à aucun cas déclaré, au lieu de tomber silencieusement dans un comportement par défaut. Une faute de frappe lors de la lecture d’une métadonnée utilisateur devient ainsi une erreur immédiate et explicite, plutôt qu’un refus d’accès dont la cause reste à deviner.
Ce que cette modélisation ne remplace pas
Les rôles et capacités natifs de WordPress, gérés via WP_Role et current_user_can(), restent le mécanisme approprié pour tout ce qui touche à l’administration standard du site : gestion des contenus, des utilisateurs, des réglages. L’enum de permissions personnalisé décrit ici s’ajoute à cette couche pour un besoin métier spécifique, sans jamais s’y substituer.
Points de vigilance lors de la migration
- Les valeurs stockées en base de données restent des chaînes de caractères : la conversion vers l’enum via
from()doit intervenir à la lecture, pas au niveau du schéma de stockage lui-même. - Envelopper l’appel à
from()dans un bloctry/catchlors de la lecture de données existantes évite qu’une valeur historique incompatible ne provoque une erreur fatale non gérée en production. - Documenter chaque cas de l’enum avec un commentaire précisant le périmètre exact qu’il couvre, pour éviter qu’un nouveau développeur ajoute un cas redondant avec un existant.
En résumé
Un enum backé par PHP 8.1 transforme une hiérarchie de permissions modélisée en chaînes de caractères libres en un ensemble fermé de valeurs vérifiées à la lecture. Les fautes de frappe et incohérences de nommage, auparavant absorbées silencieusement par une branche par défaut, deviennent des erreurs explicites et détectables bien avant qu’un utilisateur ne se heurte à un refus d’accès inexpliqué.