The PHP 8.5 Pipe Operator: Function Chains That Read Top to Bottom cover image

The PHP 8.5 Pipe Operator: Function Chains That Read Top to Bottom

Scott Keck-Warren • September 25, 2026

There's a good chance that if you've been working with PHP for more than a hot minute, you've run into code that looks like the following:

$result = [" scott", "@", "thesteadypack.com "];
$result = implode($result);
$result = strtolower($result);
$result = trim($result);
echo $result; // scott@thesteadypack.com

It works, but we're one keystroke away from a typo that silently breaks the whole stack: $reslt.

The "fix" is to reach for nesting your code:

echo trim(strtolower(implode($result))); // scott@thesteadypack.com

This is arguably worse because now we need to read the code "inside-out," which isn't generally how our brains work.

PHP 8.5 gave us the pipe operator (|>), which allows us to drastically clean up this kind of chained function calling

What the pipe operator does

At a basic level, the pipe operator passes the left value into the right callable as its first argument. So we can rewrite our code from above like so:

$result = [" scott", "@", "thesteadypack.com "]
    |> implode(...)
    |> strtolower(...)
    |> trim(...);
echo $result; // thesteadypack.com

The important parts here are that, unlike the "original" examples above, the pipe operator version reads top-to-bottom (in the same order it executes) without having to worry about a temporary variable or inside-out nesting.

The "..." is what's really doing the work, which was something we got in an earlier version of PHP.

First-class callables and the ... syntax

So the implode(...) in our functions can be a little confusing. What's happening is that implode(...) isn't actually calling the implode() function, and instead it's building a Closure that we will reference and call later. This concept is called first-class callable syntax, and it was added in PHP 8.1. The important piece to remember is that implode(...) is the function itself handed over as a value while implode($x) runs it now.

implode($x);      // calls it, returns a string
implode(...);     // a Closure you can pass around / pipe into

The pipe operator wants a callable and not a call, which is why every stage ends in (...).

How it works under the hood

The pipe RFC is really interesting because it states that the pipe works entirely at the compiler level, so it's "just" transforming the piped form into our first example at compile time. This means there's virtually no overhead to you using the pipe operator. It's a huge payoff because your code becomes more readable with no performance tax, so you don't need to choose between fast and clear.

Limitations and gotchas

So there are some limitations (as of the time of this writing, some have proposed solutions already, so I may have to revisit this post).

It only supports callables with a single required parameter, so if the callable requires more, you'll need to use a wrapper:

$title = 'PHP 8.5 Released';

$slug = $title 
    |> (fn($str) => str_replace(' ', '-', $str)) 
    |> (fn($str) => str_replace('.', '', $str)) 
    |> strtolower(...);

var_dump($slug); // string(15) "php-85-released"

You also can't use a by-reference callable like sort(...) that mutates its arguments.

Finally, it's left-to-right logic, so if a step needs two inputs or conditional routing, then a pipe isn't the correct tool.

My honest opinion is that you shouldn't "pipe-ify" everything. A one- or two-step transformation is fine as a nested call, but pipe earns its place when we're in the 3+ stage call range.

Next Steps

Now that you know there's a better way to write chained calls, you'll never write a bunch of $result = ...; $result = ...; lines (right?). If you're already using PHP 8.5, try the pipe operator on one of your existing transform chains (maybe the one you have to squint at before it clicks). Also check out my roundup of the PHP 8.5 features, like NoDiscard, clone(), array_first/last.

AI notice:

The outline for this post was generated via AI, then I wrote the prose and ran it through Grammarly