Pipe operator |> no PHP 8.5: lendo seu código da esquerda pra direita (como a vida pede)

Deixa eu te contar uma cena que todo dev PHP já viveu. Você abre um arquivo legado, encontra uma linha tipo essa:

$slug = trim(strtolower(str_replace(' ', '-', preg_replace('/[^a-z0-9 ]/i', '', $titulo))));

E aí começa o ritual. Seu olho vai lá pro miolo, acha o preg_replace, volta um nível, lê o str_replace, sobe pro strtolower, e finalmente chega no trim lá na ponta. Você leu a coisa de dentro pra fora, na ordem inversa de como ela executa. É tipo ler um livro começando pelo capítulo do meio. Funciona, mas o cérebro reclama.

O PHP 8.5 trouxe uma resposta elegante pra isso: o pipe operator, o tal do |>. E a ideia é tão simples que dá até raiva de não ter chegado antes.

O que é o |>, sem mistério

O pipe operator pega o valor do lado esquerdo e passa como primeiro argumento do callable do lado direito. Só isso. Ele encadeia chamadas da esquerda pra direita, na mesma ordem em que os dados realmente fluem.

Aquele slug lá de cima vira isto:

$slug = $titulo
    |> fn($t) => preg_replace('/[^a-z0-9 ]/i', '', $t)
    |> fn($t) => str_replace(' ', '-', $t)
    |> strtolower(...)
    |> trim(...);

Leia em voz alta: “pega o título, tira os caracteres estranhos, troca espaço por hífen, deixa minúsculo, apara as pontas”. É exatamente a ordem em que você pensa o problema. O dado entra de um lado e vai sendo transformado, passo a passo, igual uma esteira de fábrica.

Repara em dois detalhes de sintaxe que vão te pegar no começo:

  1. Aquele strtolower(...) com as reticências é a first-class callable syntax (que existe desde o 8.1). Ela transforma a função numa referência callable sem chamar na hora. É isso que o |> espera do lado direito: algo chamável.
  2. As arrow functions (fn() => ...) à direita do pipe precisam de parênteses se você não usar a forma de variável. É uma regra de gramática proposital pra não dar ambiguidade com a precedência do operador. Guarde isso, porque o erro de parse é meio críptico.

Por que isso importa no backend de verdade

Você pode estar pensando: “Marcus, isso é açúcar sintático, eu vivo bem sem”. E vive mesmo. Mas deixa eu mostrar onde o |> para de ser firula e vira ferramenta.

No backend a gente passa o dia transformando dado. Chega um payload de um parceiro, e até ele virar um objeto de domínio confiável tem uma fila de etapas: decodifica, normaliza, sanitiza, valida, mapeia. Sem o pipe, isso costuma virar uma de duas coisas: ou um aninhamento ilegível, ou uma escada de variáveis temporárias com nomes criativos tipo $dataNormalized, $dataNormalizedSanitized, $dataNormalizedSanitizedFinal.

Com o pipe, o pipeline fica explícito:

$pedido = $payloadCru
    |> json_decode(...)
    |> normalizarChaves(...)
    |> removerCamposVazios(...)
    |> PedidoDTO::fromArray(...);

Cada função faz uma coisa. Cada uma recebe o resultado da anterior. E o leitor entende o fluxo inteiro num scroll só, sem precisar segurar cinco variáveis na cabeça. É o tipo de código que o seu eu do futuro agradece às três da manhã durante um incidente.

O detalhe que separa o pipe de uma gambiarra

Tem uma pegadinha conceitual importante aqui: o |> passa o valor como primeiro argumento. Mas e quando a função que você quer usar espera o valor num outro lugar? Tipo str_replace($busca, $troca, $sujeito), o “sujeito” é o terceiro argumento, não o primeiro.

É aqui que entra a dupla perfeita: o pipe operator combinado com Partial Function Application, que foi aprovada pra PHP 8.6 (já falei dela aqui no vault). Com ela, você pré-preenche os argumentos fixos e deixa o “buraco” exatamente onde o valor do pipe vai cair:

// Com partial application (PHP 8.6): o ? marca onde o valor entra
$slug = $titulo
    |> str_replace(' ', '-', ?)
    |> strtolower(...)
    |> trim(...);

Enquanto a 8.6 não chega, dá pra resolver com uma arrow function mesmo, sem drama:

$slug = $titulo
    |> (fn($t) => str_replace(' ', '-', $t))
    |> strtolower(...);

Não é tão bonito, mas funciona hoje, no 8.5, em produção.

“Mas isso não é só Laravel pipeline / collection?”

Boa pergunta, e a resposta é: parecido na intenção, diferente na natureza. O Pipeline do Laravel e os Collection::pipe() da vida são construções de runtime… objetos, métodos, overhead de chamada. O |> é operador de linguagem, resolvido no nível do parser. Não tem objeto intermediário, não tem classe pra carregar. É mais leve e funciona com qualquer callable, não só dentro do ecossistema de uma framework.

Isso não quer dizer que você vai jogar fora o Pipeline do Laravel, ele resolve um problema diferente, de middleware com $next, com a possibilidade de interromper o fluxo. O |> é pra transformação pura de valor, aquele caso simples e onipresente que antes não tinha uma forma elegante.

Onde NÃO usar (porque todo poder vem com responsabilidade)

Vou ser honesto pra você não sair piping tudo amanhã e me xingar depois:

  • Efeito colateral no meio do pipe é cilada. Pipe foi feito pra transformação de valor. Se uma etapa grava no banco, dispara evento ou loga, você está escondendo efeito colateral numa cadeia que parece pura. Quem lê vai se enganar.
  • Debug é diferente. Não dá pra cravar um var_dump “no meio” do operador como você faria entre duas linhas. Se precisa inspecionar etapa por etapa, talvez a escada de variáveis seja melhor naquele trecho específico.
  • Cadeia gigante também cansa. Doze pipes empilhados não são mais legíveis que três funções bem nomeadas. Bom senso continua valendo.

O impacto técnico, sem hype

O pipe operator não te deixa fazer nada que você já não conseguisse fazer. Ele não traz performance mágica nem resolve problema de arquitetura. O que ele entrega é legibilidade alinhada à execução, e isso, num código de backend que você mantém por anos, vale muito mais do que parece. Menos carga cognitiva por linha lida é menos bug introduzido na próxima alteração.

Junte o |> (8.5) com a partial application (8.6) e o PHP começa a oferecer, de forma nativa e idiomática, um estilo de composição funcional que antes a gente só conseguia importando biblioteca ou inventando helper. É o tipo de evolução silenciosa que, daqui a dois anos, vai estar em todo código novo e ninguém mais vai lembrar de como era ler função de dentro pra fora.

E convenhamos: ler da esquerda pra direita já era hora. A gente faz isso com texto desde a primeira série.

Se você ainda está no PHP 8.3 ou 8.4, o pipe operator é mais um bom motivo pra planejar o upgrade pro 8.5, que, aliás, é a versão recomendada pra projeto novo desde novembro de 2025. Comece pequeno: pegue aquele seu trecho de normalização de payload mais ilegível e reescreva com |>. Você vai sentir na hora a diferença de bater o olho e entender o fluxo em vez de decifrá-lo.

Código bom não é o mais esperto. É o que o próximo dev, provavelmente você mesmo, entende sem sofrer.