Blog
October 16, 2025
The PHP pipe operator is a new feature in PHP 8.5, which releases in November 2025, and it introduces a simpler, more readable way to chain operations together. Traditionally, PHP developers have relied on nested functions and temporary variables to transform data, leading to cluttered and hard-to-follow code. With the PHP pipe operator, you can now write clean, left-to-right expressions that make your code’s logic clear and intuitive.
In this blog, I examine the context that led to the development of the PHP pipe operator. I then go through how you can implement it within your code, helping you to hit the ground running after upgrading to PHP 8.5. Finally, I look ahead to the future and what the new pipe operator may mean for the language as a whole.
PHP Pipe Operator: Why Do We Need It?
Why was the pipe operator proposed in the first place?
Let's consider a common task: filtering or normalizing a string value. Let's say that the input is a semicolon (;) separated list of what is expected to be email addresses, and you want to ensure that before you store any in your database, you've normalized them by removing any leading or trailing whitespace, and cast them to lowercase (as email addresses are case insensitive).
You might write that code like this:
$emails = explode(';', $input);
$emails=array_filter($emails, is_string(...));
$emails=array_map(trim(...), $emails);
$emails=array_map(strtolower(...), $emails);
$emails=array_filter(
$emails,
fn (string $email): bool = > filter_var(
$email,
FILTER_VALIDATE_EMAIL | FILTER_FLAG_EMAIL_UNICODE,
null
) ! = = null
);
If you want to avoid the temporary variable assignment (all of the places the above example has $emails =
), you could nest the calls as follows:
$emails = array_filter(
array_map(
strtolower(...),
array_map(
trim(...),
array_filter(
explode(';',$input),
is_string(...)
)
)
),
fn (string $email): bool => filter_var(
$email,
FILTER_VALIDATE_EMAIL | FILTER_FLAG_EMAIL_UNICODE,
null
) !==null
);
However, this is an unreadable mess and difficult to reason about. Identifying the order of operations is unintuitive as you have to work from the inside out, making maintenance harder.
Enter: the pipe operator.
Back to topIntroducing the PHP 8.5 Pipe Operator
The PHP Pipe Operator is defined as follows:
mixed |> callable;
The operator itself is |>
. It accepts a single callable parameter on the right, and passes the left-side value to it, evaluating to the callable's result.
Where it gets its power is that you can chain the operator, and it operates left to right. So, borrowing from the previous example, we could write:
$email = $someValidEmail |> trim(...) |> strtolower(...);
This would pass $someValidEmail
to the trim()
function, and then the result of that will be passed — or piped — to the strtolower()
function, and the resulting value assigned to $email
at the end.
What is This "(...)" Syntax?
PHP 8.1 introduced the first-class callable syntax. Instead of using strings to refer to function names you wish to pass as a callable, which is prone to errors (such as misspellings) that won't be caught until runtime, you use the syntax functionname(...)
; the ellipses tell the PHP engine that the callable will operate on and accept all arguments passed to it. This is similar to how the splat operator works.
This also works for other callable syntax, such as method calls: Static::method(...
) and $instance->method(...)
. Using first-class callable syntax ensures that non-callables are caught at compile time, raising errors early. Additionally, static code analysis will find these usages for you as well, and identify problems before you deploy.
Why the PHP 8.5 Pipe Operator Matters
The pipe operator allows the PHP compiler to do some optimizations that remove the need for temporary variables, giving some memory and performance gains.
Additionally, from a coding standpoint, it can help eliminate the need to create "collection" behavior for objects. As an example, it's not uncommon to define a collection and then call methods on that collection to perform filtering, such as we had in the first example:
$emails = new Collection(explode(';', $input))
->filter(is_string(...))
->map(trim(...))
->map(strtolower(...))
->filter(fn (string $email): bool => filter_var(
$email,
FILTER_VALIDATE_EMAIL | FILTER_FLAG_EMAIL_UNICODE,
null
) !==null);
Much of the time, these filter()
and map()
methods are proxying to array_map()
or array_filter()
internally, which means that you are adding CPU overhead by wrapping them in a method call. It also means that you're already keeping a copy of the array internally, and now the garbage collector needs to clean those up once all the operations are done. This is because these methods generally return clones of the original instance.
How to Use the PHP Pipe Operator
Let's go back to the original example now, and rewrite it with the pipe operator:
$emails = explode(';',$input)
|> (fn (array $emails) => array_filter($emails,is_string(...)))
|> (fn (array $emails) => array_map(trim(...), $emails))
|> (fn (array $emails) => array_map(strtolower(...), $emails))
|> (fn (array $emails) => array_filter(
$emails,
fn (string $email): bool => filter_var(
$email,
FILTER_VALIDATE_EMAIL | FILTER_FLAG_EMAIL_UNICODE,
null
) !==null
));
Comparing this to the original example:
- We remove the need for temporary variables entirely.
- We remove reassignment, which is error prone (it's easy to mistype!).
- It becomes clear that each step is operating on the previous value, and what each step is doing.
Is it better than using a Collection object? There's certainly more syntax involved, which is a bit of a minus. Also, notice how the arrow functions are all wrapped in parentheses. This is due to a limitation of the implementation whereby the arrow functions capture to the end of the expression; wrapping them in parentheses "fixes" the issue, but is an extra bit of syntax for you to remember. However, in terms of performance, the piped version can be better optimized by the PHP compiler, which can potentially lead to performance gains.
Back to topThe Pipe Operator and the Future of PHP
Knowing that there are issues with arrow functions, is it worth using the pipe operator today? Yes. If nothing else, using the PHP 8.5 pipe operator will prepare you for the future.
One RFC that did not get to the voting stage for 8.5 is for partial function application. This RFC proposes syntax changes that would allow providing a combination of static values and placeholders when specifying a first class callable. While the details of placeholders are still being debated, the general idea is that a ?
will likely indicate a single argument to fill, while ...
will indicate any remaining arguments should be inserted. There's some debate around allowing named arguments as well.
Should partial function application make it into the language, the above example becomes even simpler, as we can eliminate the arrow functions entirely:
$emails = explode(';',$input)
|> array_filter(?, is_string(...))
|> array_map(trim(...), ?)
|> array_map(strtolower(...), ?)
|> array_filter(?, filter_var(
?,
FILTER_VALIDATE_EMAIL | FILTER_FLAG_EMAIL_UNICODE,
null
));
At that point, the PHP pipe operator provides substantial readability over both the current syntax where we do reassignment, as well as over using Collection classes to do basic array operations. Combine that with the compiler optimizations, and we have some incredible power available from a very simple operator.
In the future, I fully expect tools like Rector to be able to refactor arrow functions that simply proxy to functions internally to partial function applications, so starting to use them now will make it easier to adopt the syntax once it's available.
Back to topFinal Thoughts
The PHP 8.5 pipe operator represents a meaningful step toward cleaner and more expressive code. It helps you to eliminate repetitive variable assignments and nested calls, which in turn makes data transformations easier to read and maintain. As PHP continues to evolve, the pipe operator is positioned to become a key part of functional-style programming. Adopting it early will simplify your code today while preparing your projects for future changes.
Upgrade to PHP 8.5 On Your Schedule
PHP 8.5 releases on November 20, 2025. Make the Zend experts your experts during your upgrade. Extend the lifespan of your current PHP version with long-term support, stay secure with backported security patches, and access 24/7/365 technical assistance.
Additional Resources
- White Paper - The Hidden Costs of PHP Upgrades
- White Paper - Planning Your Next PHP Migration
- Blog - Creating a PHP 8.1 Upgrade Plan Before EOL
- Blog - PHP Installer for Extensions (PIE): What to Know Before General Release
- Blog - When (And When Not) to Use Laravel Shift to Update Laravel
- Blog - PHP Dependency Management Using Composer