# Union types de PHP 8 pour typer un argument de template qui accepte deux formes

> Une fonction de template part-elle d'un identifiant ou d'un objet WP_Post ? Les union types de PHP 8 permettent de le déclarer sans dupliquer le code.

- Auteur : WordPress Développement
- Publié le : 2023-04-19
- Mis à jour le : 2026-09-30
- Catégorie : Éditeur de site (FSE)
- URL : https://www.wpmoderne.fr/fse/union-types-php8-argument-template-deux-formes/

## L’essentiel

- Déclarer int ou WP_Post plutôt que de dupliquer deux fonctions
- Normaliser l'argument en une seule ligne avec get_post()
- Garder un retour de type strict pour la suite de la chaîne

`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

> L'essentiel à retenir : Déclarer int ou WP_Post plutôt que de dupliquer deux fonctions ; Normaliser l'argument en une seule ligne avec get_post() ; Garder un retour de type strict pour la suite de la chaîne

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|null` quand la fonction doit explicitement accepter l'absence de source, par exemple lorsqu'un bloc n'a pas encore de contenu associé ;
- `string|WP_Term` pour 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|false` quand 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.
