Le côté droit du nouvel opérateur |> de PHP 8.5 doit être un callable, pas un appel de fonction. Tout ce qui est intéressant dans cette fonctionnalité se cache dans cette exigence. L'opérateur lui-même tiendrait sur un post-it : il évalue l'expression à sa gauche et passe le résultat comme premier argument à ce qui se trouve à sa droite. Tu écris donc $input |> trim(...), en t'appuyant sur la syntaxe des callables de première classe qu'on a eue avec la 8.1. Mais dès qu'une étape a besoin d'un deuxième argument, disons un str_replace avec une recherche et un remplacement, tu dois l'envelopper : (fn($s) => str_replace(' ', '-', $s)), et les parenthèses extérieures ne sont pas décoratives. Enlève-les et la fonction fléchée capture goulûment le reste de la chaîne, et le parseur t'abandonne.
<?php
// PHP 8.5: each step takes a value, returns a value
function sanitizeComment(string $input): string
{
return $input
|> trim(...)
|> strip_tags(...)
|> (fn($s) => htmlspecialchars($s, ENT_QUOTES, 'UTF-8'));
}Cet emballage est la plainte que j'entends le plus souvent au sujet de l'implémentation actuelle, et oui, PHP 8.6 devrait apporter l'application partielle de fonctions pour te permettre de pré-remplir des arguments et de te débarrasser de la plupart de ces closures. J'espère qu'elle prendra son temps. Cette verbosité fait un discret travail pédagogique. Chaque fois que tu tapes fn($s) =>, le langage te pose une petite question pointue : est-ce que cette étape est vraiment une cale anonyme, ou est-ce une chose avec un nom dont ta base de code voudra encore mardi prochain ?
Parce que quand les étapes reçoivent des noms, l'opérateur mérite soudain sa place. Les méthodes statiques se pipent directement avec la syntaxe callable, donc $raw |> Slug::normalize(...) |> Slug::truncate(...) se lit de haut en bas sans aucune cérémonie. Les méthodes d'instance n'ont pas ce luxe, tu dois encore envelopper $formatter->format() dans une closure, ce qui est une verrue authentique, mais cela signifie aussi que le code pipé dérive vers de petites fonctions sans état avec une entrée évidente. Cette dérive est gratuite à l'exécution : les chaînes de pipes compilent vers des opcodes à peu près équivalents aux appels imbriqués que tu aurais écrits de toute façon, donc il n'y a aucune facture de performance à découper ton pipeline en une douzaine de petits morceaux nommés.
Maintenant, la partie honnête. L'argument le plus fort contre le fait de s'embêter avec |>, c'est que PHP avait déjà une réponse parfaitement fonctionnelle : les variables intermédiaires. $trimmed, $slugified, $lowercased. Ces noms documentent l'intention, ils apparaissent dans ton débogueur, tu peux faire un var_dump sur n'importe laquelle sans cérémonie. Une chaîne de pipes ne t'offre rien de tout ça, et elle ajoute un piège que l'ancien style n'avait pas : un callable void s'évalue à null, donc si tu balances un var_dump au milieu d'une chaîne pour jeter un coup d'œil rapide, l'étape suivante reçoit null au lieu de ta valeur et le pipeline empoisonne silencieusement tout ce qui suit. Pas d'exception, pas d'avertissement, juste une sortie fausse trois étapes plus loin. Ajoute la réalité du déploiement, c'est une nouvelle syntaxe qui ne parsera pas sur 8.4 ni sur rien de plus ancien, donc toute ta flotte et tes runners de CI doivent d'abord passer en 8.5, et le scepticisme paraît assez raisonnable.
J'atterris quand même du côté de l'utiliser, et le piège du var_dump fait partie des raisons. Une chaîne de pipes fait une promesse que la version avec variables n'énonce jamais vraiment : chaque étape prend une valeur et retourne une valeur, rien d'autre ne se passe ici. Les effets de bord ne collent pas à la forme, et en revue de code ce décalage se voit depuis l'autre bout de la pièce. Quand un collègue essaie de glisser en douce un appel au logger au milieu d'une transformation, la chaîne elle-même proteste. Avec quatre variables temporaires, ce même appel au logger se faufile entre les affectations et personne ne bronche. L'opérateur ne te permet rien de nouveau. Il change ce qui a l'air faux, et après suffisamment d'années à maintenir le code de sanitization des autres, j'en suis venu à valoriser ça plus que le confort du débogueur.
Donc ma règle de travail depuis l'arrivée de la 8.5 : des pipes pour tout ce qui est honnêtement une transformation, les constructeurs de slugs, les sanitizers d'entrées, la danse filter-map-unique-values sur les tableaux. De bonnes vieilles variables pour tout ce qui comporte des branchements, des retours anticipés ou un usage lourd de l'état d'un objet, là où une chaîne ne serait qu'un déguisement. L'outillage ne te fera pas la guerre, PhpStorm et Intelephense dans VS Code comprennent tous les deux la syntaxe depuis début 2026. Et si une chaîne accumule plus de deux closures inline, je m'arrête et j'extrais des fonctions nommées avant de merger, parce que cette chaîne me dit que le domaine a un vocabulaire que je n'ai pas encore couché sur le papier.
La communauté Elixir a |> depuis avant que certains de nos codes legacy ne soient legacy, et F# avant elle, donc PHP arrive en retard à cette fête. Très bien. On est arrivés avec de l'optimisation au niveau d'opcache et les callables de première classe déjà dans la boîte à outils, ce qui est une manière décente d'arriver en retard. Ma question ouverte concerne la 8.6 : une fois que l'application partielle aura atterri et que les emballages (fn($s) => ...) se seront évaporés, continueras-tu à extraire des étapes nommées, ou est-ce que la taxe sur les parenthèses était la seule chose qui gardait tes pipelines honnêtes ? Autrement dit, combien de closures inline tolères-tu dans une chaîne avant de bloquer la merge request ? Je dis deux. Dis-moi pourquoi j'ai tort.




Commentaires
Pas encore de commentaire — écris le premier.
Lance la discussion
Pas de compte ni de mot de passe — saisis simplement ton adresse e-mail et nous t’envoyons un lien de connexion à usage unique. Première visite ? Tout se met en place automatiquement.
Ton évaluation sera appliquée automatiquement après ta connexion.
Vérifie ta boîte mail
Nous avons envoyé un lien de connexion à …. Ouvre-le sur cet appareil — cet onglet te connectera automatiquement.
Rien reçu ? Vérifiez le dossier spam — et marquez le message « Non spam » pour qu'il arrive directement la prochaine fois.