function render_hero( int|WP_Post $source ): string — cette signature n’aurait tout simplement pas compilé avant PHP 8.0. Avant les union types, une fonction de template qui devait accepter aussi bien un identifiant d’article qu’un objet WP_Post obligeait soit à typer l’argument en mixed avec un simple commentaire pour expliquer les formes attendues, soit à écrire deux fonctions distinctes qui finissaient presque toujours par diverger au fil des correctifs.
Ce cas revient souvent dans les fonctions utilitaires d’un thème de blocs, en particulier dans les template parts qui doivent afficher un aperçu d’article aussi bien depuis une Query Loop, où l’on dispose d’un objet complet, que depuis un appel direct dans un template, où l’on n’a parfois qu’un identifiant en base. Voici comment nous typons désormais ce genre d’argument, et ce que les union types changent concrètement dans la lisibilité du code.
Le problème avant PHP 8
Sans union type, une signature comme function render_hero( $source ) ne documente rien : rien n’empêche d’appeler la fonction avec une chaîne de caractères par erreur, et l’IDE ne peut proposer aucune complétion pertinente sur le paramètre. Le corps de la fonction devait alors commencer par une série de vérifications défensives, répétées dans chaque fonction du même genre :
function render_hero( $source ) {
if ( is_numeric( $source ) ) {
$post = get_post( (int) $source );
} elseif ( $source instanceof WP_Post ) {
$post = $source;
} else {
return '';
}
// ...
}
La même fonction avec un union type

Avec PHP 8, la déclaration int|WP_Post documente directement les deux formes acceptées, et PHP lève une TypeError si l’appelant passe autre chose. La vérification interne reste nécessaire pour distinguer les deux cas, mais elle n’a plus à couvrir les cas invalides :
function render_hero( int|WP_Post $source ): string {
$post = $source instanceof WP_Post ? $source : get_post( $source );
if ( ! $post instanceof WP_Post ) {
return '';
}
return sprintf(
'<div class="hero"><h2>%s</h2></div>',
esc_html( get_the_title( $post ) )
);
}
Le type de retour string est également explicite : la fonction ne renvoie jamais null ni false, ce qui simplifie l’appel dans un template où l’on veut juste échapper la sortie sans vérification supplémentaire.
Ce que ça change pour les appelants
Un appelant qui passe un mauvais type — un tableau, par exemple, résultat fréquent d’une Query Loop mal filtrée — obtient désormais une erreur immédiate et explicite au lieu d’un comportement silencieux plus loin dans le rendu :
Fatal error: Uncaught TypeError: render_hero(): Argument #1 ($source) must be of type int|WP_Post, array given
C’est un vrai gain en développement : l’erreur remonte à l’endroit de l’appel fautif plutôt que dans une fonction utilitaire appelée dix fichiers plus loin.
Variantes utiles
int|WP_Post|nullquand la fonction doit explicitement accepter l’absence de source, par exemple lorsqu’un bloc n’a pas encore de contenu associé ;string|WP_Termpour une fonction qui affiche une étiquette de taxonomie à partir d’un slug ou d’un objet déjà résolu ;- un type de retour
string|falsequand l’échec doit rester distinguable d’une chaîne vide légitime, ce qui évite de confondre « rien à afficher » et « erreur ».
Une limite à connaître
Les union types ne remplacent pas une vérification métier. Typer int|WP_Post garantit la forme de la donnée, pas sa validité : un identifiant numérique qui ne correspond à aucun article existant reste un cas à gérer explicitement, comme le montre le get_post() dans l’exemple ci-dessus, dont le retour peut être null.
Nous réservons les union types aux arguments réellement ambigus. Sur un argument qui n’accepte qu’une seule forme, un type strict classique reste plus lisible qu’une union inutile.
Ce qu’on retient de ce changement
Les union types ne rendent pas un thème plus rapide, mais ils suppriment une catégorie entière de bugs silencieux liés à des arguments mal formés. Sur les thèmes de blocs que nous maintenons, la migration progressive de mixed vers des unions explicites a fait remonter, dès les premières semaines, plusieurs appels avec des types qui ne correspondaient déjà plus à ce que les fonctions étaient censées recevoir.