PHP 10 décembre 2025 10 min de lecture

PHP 8.5 : L'opérateur Pipe (|>), la révolution du chaînage fonctionnel

Gabriel Janez

Gabriel Janez

Développeur Full-Stack PHP

PHP 8.5 introduit enfin l'opérateur |> (Pipe), attendu depuis des années par la communauté. Après deux tentatives de RFC infructueuses, la troisième version a été acceptée et intégrée. Cet opérateur révolutionne la façon de chaîner les fonctions en PHP.

Le problème : les appels de fonctions imbriqués

Avant PHP 8.5, pour enchaîner plusieurs transformations sur une valeur, nous avions deux options peu élégantes :

Option 1 : L'imbrication (illisible)

// Lecture de droite à gauche... 😵
$result = array_sum(
    array_filter(
        array_map(
            fn($n) => $n * 2,
            $numbers
        ),
        fn($n) => $n > 10
    )
);

// Ou en une ligne illisible
$result = trim(strtoupper(str_replace(' ', '-', $string)));

Option 2 : Les variables intermédiaires (verbeux)

// Variables temporaires partout... 😮‍💨
$doubled = array_map(fn($n) => $n * 2, $numbers);
$filtered = array_filter($doubled, fn($n) => $n > 10);
$result = array_sum($filtered);

Ces deux approches posent problème :

  • Imbrication : difficile à lire, ordre inversé de l'exécution
  • Variables temporaires : code verbeux, pollution du scope

La solution : l'opérateur Pipe |>

L'opérateur Pipe permet de chaîner les fonctions de gauche à droite, dans l'ordre naturel de lecture :

// PHP 8.5 - Élégant et lisible ! 🎉
$result = $numbers
    |> array_map(fn($n) => $n * 2, ...)
    |> array_filter(fn($n) => $n > 10, ...)
    |> array_sum(...);

// Chaînage de strings
$slug = $title
    |> strtolower(...)
    |> trim(...)
    |> preg_replace('/[^a-z0-9]+/', '-', ...);

Le résultat de chaque expression est passé comme premier argument de la fonction suivante.

Syntaxe et fonctionnement

Syntaxe avec first-class callables

L'opérateur Pipe utilise la syntaxe des first-class callables introduite en PHP 8.1 avec les (...) :

// Fonctions natives
$result = "Hello World"
    |> strtoupper(...)     // "HELLO WORLD"
    |> str_split(...)      // ['H','E','L','L','O',' ','W','O','R','L','D']
    |> array_reverse(...)  // ['D','L','R','O','W',' ','O','L','L','E','H']
    |> implode('', ...);   // "DLROW OLLEH"

echo $result; // DLROW OLLEH

Avec des fonctions utilisateur

function double(int $n): int {
    return $n * 2;
}

function addTax(float $amount): float {
    return $amount * 1.20;
}

function formatPrice(float $amount): string {
    return number_format($amount, 2, ',', ' ') . ' €';
}

$price = 100
    |> double(...)       // 200
    |> addTax(...)       // 240.0
    |> formatPrice(...); // "240,00 €"

Avec des méthodes statiques

class StringHelper {
    public static function slugify(string $text): string {
        return strtolower(preg_replace('/[^a-z0-9]+/i', '-', $text));
    }
    
    public static function truncate(string $text, int $length = 50): string {
        return strlen($text) > $length 
            ? substr($text, 0, $length) . '...' 
            : $text;
    }
}

$slug = "Mon Super Article de Blog !"
    |> StringHelper::slugify(...)   // "mon-super-article-de-blog-"
    |> trim('-', ...);              // "mon-super-article-de-blog"

Avec des arrow functions

// ⚠️ Les arrow functions nécessitent des parenthèses
$result = 5
    |> (fn($n) => $n * 2)      // 10
    |> (fn($n) => $n + 3)      // 13
    |> (fn($n) => "Total: $n"); // "Total: 13"

⚠️ Parenthèses obligatoires pour les arrow functions

Sans parenthèses, l'arrow function "capture" tout jusqu'à la fin de l'expression, causant des erreurs de parsing.

Cas d'utilisation concrets

Traitement de données

// Traitement d'une liste d'utilisateurs
$activeEmails = $users
    |> array_filter(fn($u) => $u->isActive(), ...)
    |> array_map(fn($u) => $u->email, ...)
    |> array_unique(...)
    |> array_values(...);

// Pipeline de validation
$sanitizedInput = $request->input('name')
    |> trim(...)
    |> strip_tags(...)
    |> htmlspecialchars(...);

Manipulation de fichiers

// Lecture et parsing d'un fichier JSON
$config = '/path/to/config.json'
    |> file_get_contents(...)
    |> json_decode(..., true)
    |> array_merge(['defaults' => true], ...);

Génération de contenu

// Génération d'un slug SEO-friendly
function generateSlug(string $title): string {
    return $title
        |> mb_strtolower(...)
        |> (fn($s) => preg_replace('/[àáâãäå]/u', 'a', $s))
        |> (fn($s) => preg_replace('/[èéêë]/u', 'e', $s))
        |> (fn($s) => preg_replace('/[ìíîï]/u', 'i', $s))
        |> (fn($s) => preg_replace('/[^a-z0-9]+/', '-', $s))
        |> trim('-', ...);
}

echo generateSlug("L'été à Paris !"); // "l-ete-a-paris"

Calculs en chaîne

// Calcul de prix avec remises
function calculateFinalPrice(
    float $basePrice, 
    float $discount, 
    bool $isPremium
): string {
    return $basePrice
        |> (fn($p) => $p * (1 - $discount / 100))
        |> (fn($p) => $isPremium ? $p * 0.9 : $p)
        |> (fn($p) => $p * 1.20) // TVA
        |> round(2, ...)
        |> number_format(2, ',', ' ', ...)
        |> (fn($p) => "$p €");
}

echo calculateFinalPrice(100, 10, true); // "97,20 €"

Limitations importantes

1. Un seul paramètre requis

Chaque callable doit accepter exactement un paramètre requis (le résultat précédent) :

// ✅ Fonctionne - un paramètre requis
function double(int $n): int {
    return $n * 2;
}

// ❌ Ne fonctionne PAS - deux paramètres requis
function multiply(int $a, int $b): int {
    return $a * $b;
}

// ✅ Solution - utiliser une arrow function
$result = 5
    |> (fn($n) => multiply($n, 3)); // 15

2. Position du paramètre fixe

Le résultat est toujours passé en premier argument. Si vous avez besoin d'une autre position :

// str_replace($search, $replace, $subject)
// Le sujet est en 3ème position...

// ❌ Ne fonctionne pas directement
$result = $text |> str_replace('foo', 'bar', ...);

// ✅ Solution avec arrow function
$result = $text |> (fn($s) => str_replace('foo', 'bar', $s));

3. Pas de passage par référence

// ❌ Ne fonctionne pas - sort() modifie par référence
$sorted = $array |> sort(...);

// ✅ Alternative
$sorted = $array;
sort($sorted);

4. Fonctions void

// ⚠️ Les fonctions void retournent null
function logValue(mixed $value): void {
    error_log(print_r($value, true));
}

// $result vaut null après logValue
$result = "test"
    |> strtoupper(...)
    |> logValue(...)  // Retourne null !
    |> strlen(...);   // strlen(null) = 0

Priorité des opérateurs

L'opérateur Pipe a une priorité basse, ce qui permet des comportements intuitifs :

// Les comparaisons fonctionnent comme attendu
$isLong = $text 
    |> strlen(...) 
    > 100;  // true si longueur > 100

// Équivalent à :
$isLong = (strlen($text)) > 100;

Comparaison avant/après

Avant PHP 8.5Avec Pipe (PHP 8.5)
trim(strtoupper($s))$s |> strtoupper(...) |> trim(...)
Lecture droite → gaucheLecture gauche → droite ✓
Variables temporairesChaînage direct ✓
Imbrication profondePipeline linéaire ✓

L'avenir : Partial Function Application

Un RFC complémentaire est en cours de développement : Partial Function Application. Il permettrait de pré-remplir certains arguments :

// Futur potentiel (RFC en cours)
$result = $text
    |> str_replace('foo', 'bar', ?)  // ? = placeholder
    |> substr(?, 0, 100);

// Au lieu de :
$result = $text
    |> (fn($s) => str_replace('foo', 'bar', $s))
    |> (fn($s) => substr($s, 0, 100));

Conclusion

L'opérateur Pipe |> est une addition majeure à PHP 8.5 qui :

  • Améliore la lisibilité : le code se lit de gauche à droite
  • Réduit la verbosité : plus besoin de variables temporaires
  • Encourage le style fonctionnel : composition de fonctions élégante
  • Modernise PHP : alignement avec d'autres langages (Elixir, F#, Hack)

Bien qu'il ait des limitations (un seul paramètre, position fixe), l'opérateur Pipe transforme la façon d'écrire du code PHP et ouvre la porte à un style de programmation plus fonctionnel.

Si vous êtes sur PHP 8.5, commencez dès maintenant à l'utiliser dans vos pipelines de traitement de données !

Tags

Bonnes pratiques PHP PHP 8.5 Pipe Operator Programmation fonctionnelle Syntaxe

Partager

Articles similaires

Besoin d'aide sur votre projet ?

Discutons de vos besoins et trouvons ensemble la meilleure solution technique.

Me contacter