PHP 8.1, publié fin novembre 2021, introduit un type de retour peu spectaculaire mais redoutablement précis : never. Une fonction déclarée avec ce type ne rend jamais la main à l’appelant, ni en renvoyant une valeur, ni même en terminant normalement son exécution : elle lève systématiquement une exception, appelle exit, ou redirige puis interrompt le script.
Ce type se distingue de void, qui signifie qu’une fonction ne renvoie aucune valeur utile mais continue normalement son exécution jusqu’à sa fin. La nuance, subtile en apparence, change concrètement ce qu’un analyseur statique peut déduire du code qui suit l’appel de la fonction.
Le cas d’usage typique : une méthode de garde
Dans une extension qui protège l’accès à un écran d’administration personnalisé, une méthode de garde vérifie une condition et interrompt systématiquement l’exécution si elle échoue, par exemple en refusant l’accès ou en redirigeant vers une autre page.
final class GardeAcces
{
public static function exigerCapacite( string $capacite ): never
{
if ( current_user_can( $capacite ) ) {
return;
}
wp_die( 'Accès refusé.', 403 );
}
}
Cette signature contient volontairement une incohérence apparente : le corps de la méthode contient un return; sans valeur dans le cas où la vérification réussit, alors que le type déclaré est never. En réalité, PHP interdit ce cas de figure : une méthode typée never ne doit jamais contenir de return, même vide, sous peine d’erreur fatale à l’exécution. La méthode ci-dessus doit être corrigée pour ne jamais retourner normalement.
Une signature cohérente avec never

final class GardeAcces
{
public static function exigerCapacite( string $capacite ): void
{
if ( ! current_user_can( $capacite ) ) {
self::refuser();
}
}
private static function refuser(): never
{
wp_die( 'Accès refusé.', 403 );
}
}
Ici, refuser() porte légitimement le type never : elle ne fait qu’appeler wp_die(), qui termine l’exécution du script (en dehors du contexte de test unitaire, où son comportement est filtrable). La méthode publique exigerCapacite(), elle, reste typée void, car elle peut légitimement rendre la main normalement si la capacité est présente.
Ce que l’analyseur statique en déduit
L’intérêt principal de never ne se voit pas à l’exécution, mais à l’analyse statique du code, via des outils comme PHPStan ou Psalm. Un appel à une fonction typée never signale à l’outil que tout le code placé après cet appel, dans le même bloc, est inatteignable :
function traiter_requete( ?WP_User $utilisateur ): string {
if ( null === $utilisateur ) {
GardeAcces::refuser(); // typée never
}
// À partir d'ici, l'analyseur sait que $utilisateur n'est plus null.
return $utilisateur->display_name;
}
Sans le type never, un analyseur statique strict continuerait de considérer que $utilisateur peut valoir null à la ligne suivante, et signalerait une erreur potentielle sur l’accès à display_name. Le type never élimine cette fausse alerte en documentant explicitement, au niveau du langage, que le flux d’exécution ne peut pas se poursuivre au-delà de l’appel.
Pièges à éviter
- Une méthode typée
neverne peut contenir aucunreturn, même sans valeur : PHP lève une erreur fatale si ce cas se présente. - Le type
nevern’est pas compatible avec une interface qui déclarerait la même méthode envoid: la covariance de type l’autorise dans un sens (une classe fille peut resserrervoidennever), pas dans l’autre. - Une boucle infinie sans
exitni exception ne justifie pasneverà elle seule : le type concerne l’absence de retour à l’appelant, pas la durée d’exécution.
Le repère que je retiens pour choisir entre
voidetnever: si un lecteur pressé du code peut légitimement se demander « et si la fonction revient quand même ? », c’est queneverapporte une clarté quevoidne donne pas.
En résumé
Le type never, disponible depuis PHP 8.1, documente précisément qu’une fonction interrompt systématiquement l’exécution, avec un bénéfice concret pour l’analyse statique du code qui suit son appel. Ce sujet porte sur la déclaration de ce type précis ; la gestion d’erreurs dans son ensemble, avec les exceptions et leur hiérarchie, reste un sujet bien plus large qui dépasse cette seule annotation.