Konečně! Boucháme šampaňské, trháme konfety a rituálně pálíme učebnice procedurálního programování. PHP 8.5 přináší legendární Pipe Operátor |>. Svatý grál všech, kdo se po nocích modlí k bohům funkcionálního programování a tajně závidí hipstrům v Elixiru nebo F#.

Už žádné vnořování funkcí do sebe jako ruská matrjoška. Žádné pomocné proměnné typu $tmp1, $tmp2, $tmp47. Píšeme tok dat zleva doprava, přesně tak, jak přirozeně myslíme!

Marketingové oddělení PHP by vám na slidech ukázalo tohle:

$vysledek = " Ahoj " |> trim(...) |> strtoupper(...);

„Wow! To je čistota! To je elegance!“ křičí dav a hází podprsenky na pódium.

Jenže pak se probudíte a zjistíte, že realita je úplně jiná. Vítejte v pekle závorek, anonymních funkcí a výkonnostního masochismu. Pojďme se podívat, proč je tahle novinka skvělá asi tak jako nepromokavý čajový sáček.

Case Study: Jak napsat to samé, ale složitěji

Představte si klasický scénář: Chcete normalizovat text pro anglické titulky. Postup: oříznout mezery, rozsekat na slova, každému slovu dát velké počáteční písmeno a zase to slepit dohromady.

Srovnejte sami:

// Tradiční vnořování - nečitelná hrůza (Matrjoška style)
$result = implode(' ', array_map(ucfirst(...), preg_split('/\s+/', trim($input))));

// S pipe operátorem - WOW! 🎉
$result = $input
    |> trim(...)
    |> preg_split('/\s+/', ...)
    |> array_map(ucfirst(...), ...)
    |> implode(' ', ...);

Na první pohled je to zenová zahrada. Vidíte, jak data tečou shora dolů jako vodopád. Váš mozek vrní blahem, protože nemusí luštit závorky od středu ven. Je to jako číst recept: „Vezmi vstup, ořízni ho, rozsekej na slova, uprav, slep.“ Nádhera. Feng-shui v praxi.

TAKLE TO ALE NEFUNGUJE!

Ten krásný příklad výše je totiž sprostá syntaktická lež. PHP parser by se při pokusu o zpracování tohoto kódu zakuckal a umřel s výkřikem SYNTAX ERROR.

Hned si vysvětlíme proč.

Jak se to dělalo dříve

Tradiční nečitelnou hrůzu se zanořováním jsme si už ukázali. Místo toho se podívejme na „sedlácký“ styl, který všichni tajně používáme, když se nikdo nedívá:

// Tradiční způsob s pomocnými proměnnými - jasný, funkční, nudný (110 znaků)
$_ = trim($input);                             // odstranění mezer
$_ = preg_split('/\s+/', $_);                  // rozdělení na slova
$_ = array_map(ucfirst(...), $_);              // zvětšení písmen
$processed = implode(' ', $_);                 // spojení zpět

Jasný, čitelný. Každý junior ví, co se děje. Pomocná proměnná $_ sice nevyhraje soutěž krásy, ale funguje, nic nestojí a nepřekáží.

A mimochodem, tento kód má 110 znaků. Zapamatujte si to číslo.

První facka: ... není Partial Application

Placeholder ... funguje JENOM tehdy, když pipujete do prvního a zároveň jediného parametru!

Takže zatímco trim(...) je v pohodě, cokoliv složitějšího narazí do zdi. PHP (na rozdíl od jazyků, kde to dělají pořádně) neumí říct „tady je funkce a tohle je díra pro argument“.

A protože většina funkcí v PHP má pořadí parametrů vybrané generátorem náhodných čísel (needle/haystack chaos), musíte použít arrow funkce. Připravte si prsty, budete psát hodně fn, $_ a šipek:

$processed = $input
    |> trim(...)                               // Jediný moment, kdy to funguje hezky
    |> fn($_) => preg_split('/\s+/', $_)       // Arrow fce. Proměnná.
    |> fn($_) => array_map(ucfirst(...), $_)   // Vnořená arrow funkce, mňam.
    |> fn($_) => implode(' ', $_);

Druhá facka: Závorkové peklo

Spustíte to a čekáte potlesk. Místo toho na vás PHP interpreter vyplázne:
Fatal error: Arrow functions on the right hand side of |> must be parenthesized.

Pardon? Musím dávat arrow funkce do závorek? Proč? Kvůli precedenci operátorů. Parser je zmatený jak lesní včela, takže mu musíte každou arrow funkci explicitně zabalit, aby pochopil, kde končí a kde začíná další trubka.

Takže váš „elegantní“ kód nyní vypadá takto:

$processed = $input
    |> trim(...)
    |> (fn($_) => preg_split('/\s+/', $_))     // Závorka. Arrow fce. Proměnná. Závorka.
    |> (fn($_) => array_map(ucfirst(...), $_)) // Další závorky...
    |> (fn($_) => implode(' ', $_));           // Proč si to děláme?

Gratuluji! Váš kód je nyní:

  • O 53 % delší než varianta s pomocnými proměnnými (nyní má 169 znaků).
  • Vizuálně připomíná LISP po lobotomii (samá závorka).
  • Má overhead z vytváření closure při každém kroku.

Pokrok nezastavíš!

K.O.: Reference? Zapomeňte

Tohle je část, kde se smích mění v pláč a skřípění zubů. Představte si, že chcete v textu něco nahradit a zajímá vás, kolikrát k nahrazení došlo (parametr &$count u str_replace).

V klasickém „zastaralém“ kódu byste prostě předali proměnnou odkazem.

$_ = str_replace('!', '', $_, count: $count); // $count se vesele inkrementuje

Ale v arrow funkcích uvnitř roury? Smůla. Arrow funkce (fn) v PHP nemůžou měnit vnější proměnné.

Podívejte se na tuhle past:

$count = 0;

// Očekáváme, že se $count zvýší...
$processed = $input
    |> (fn($_) => str_replace('!', '', $_, count: $count)) // Zrada!
    |> trim(...)
    ...

echo $count; // Výsledek je vždy 0. Nula. Zero.

Co se stalo?

Nic. Žádná chyba. Žádná Notice. Žádný Warning. PHP prostě mlčky vzalo kopii nuly, poslalo ji do funkce, ta ji vesele inkrementovala uvnitř své bubliny a pak ji zahodila do koše. Vaše původní proměnná $count zůstala nedotčena.

Pokud to chcete opravit, musíte použít starou syntaxi function($_) use (&$count) { return ... }, čímž jste právě ztratili poslední zbytky důstojnosti a elegance.

Co se děje pod kapotou? (Spoiler: Nic hezkého)

Možná si říkáte: „No dobře, je to hnusné, ale určitě je to super rychlé, optimalizované makro, ne?“

(Nikdo soudný si tohle neříká, ale předstírejme to.)

Pipe operátor není chytré makro, které by kód přepsalo (fn($_) => ...) na prosté volání. Každý ten krok reálně vytváří novou instanci objektu Closure. Pro každou operaci. Pro každý řádek.

Takže místo prostého zavolání funkce PHP interně dělá tohle:

  1. Vytvoř objekt Closure.
  2. Zavolej ho.
  3. Zahoď ho (a nech garbage collector, ať si to užije).
  4. Opakuj pro další řádek.

Je to, jako byste si na cestu do ledničky pro pivo pokaždé objednali Uber. Dostanete se tam, ale je to zbytečně drahé, trvá to déle a sousedi si o vás budou myslet svoje.

Typehintujeme, nebo ne?

Tohle je hamletovská otázka moderního PHP. V řetězci pipe operátorů se musíte rozhodnout:

Varianta A: Jsem poctivý masochista a napíšu (fn(string $_): array => ...).

Výsledek: Kód je tak dlouhý, že se nevejde na dva monitory vedle sebe. Upíšete si ruce a kolegové vás budou nenávidět při každém Code Review.

Varianta B: Jsem lenoch a punker a napíšu jen (fn($_) => ...).

Výsledek: Vaše IDE přestane našeptávat a přísně nastavená statická analýza (PHPStan) začne křičet „Mixed type everywhere!“

Je to volba mezi karpálním tunelem a programováním naslepo.

Verdikt

Pipe operátor v PHP 8.5 je jako drahý, designový odšťavňovač, co jste si koupili v lednu v záchvatu zdravého životního stylu. Vypadá hezky na lince, všem o něm vyprávíte, ale když ho máte reálně použít, zjistíte, že umytí těch sítek trvá třikrát déle než snězení celého pomeranče i se slupkou.

Pipe operátor dává smysl pouze tehdy, když:

  1. Všechny funkce berou jeden parametr. ✅
  2. Nebo vás nezajímá výkon. ✅
  3. Nebo milujete závorky. ✅

Čili… je to skvělé do tutoriálů a na konference!

Doporučení: Zůstaňte u pomocných proměnných. Jsou levné, fungují, neodstíní reference a nemusíte kvůli nim psát (fn($_) => ...) desetkrát za sebou.


P.S.: V PHP 8.6 to vyřeší Partial Function Application. Ale utěšovat se tím teď, to je jako říct hladovému člověku: „Vydrž, příští rok už ten řízek bude i s masem.“