What Is the PHP 8.5 Pipe Operator?
PHP 8.5 (released November 2025) officially introduces the pipe operator (|>), one of the most requested syntax features in PHP’s history. Authored by Larry Garfield as part of the “Pipe Operator v3” RFC, it lets you pass the result of one expression directly as input to the next function — creating a clean, left-to-right data flow instead of deeply nested function calls.
If you’ve used pipelines in Elixir, F#, Hack, or even Unix shell commands (cat file | grep "x" | sort), this will feel instantly familiar.
$result = strtoupper("Hello World") |> str_shuffle(...) |> trim(...);
The value on the left is passed as the first argument to the callable on the right.
The Problem It Solves
PHP code that applies multiple transformations to a value traditionally ends up deeply nested and hard to read.
Old Way (Nested Calls)
$result = strtoupper(
trim(
htmlspecialchars($input)
)
);
You have to read from the inside out to understand the order of operations — and it only gets worse as more steps are added.
New Way (Pipe Operator)
$result = $input
|> htmlspecialchars(...)
|> trim(...)
|> strtoupper(...);
Now the code reads top-to-bottom, in the exact order the transformations happen.
Basic Syntax Example
$name = " john doe ";
$result = $name
|> trim(...)
|> ucwords(...);
echo $result; // John Doe
Note the ... — this is PHP’s first-class callable syntax, required so the pipe knows which function to call.
Real-World Example 1: Sanitizing Email Input
Old Way
$email = strtolower(
trim(
filter_var($email, FILTER_SANITIZE_EMAIL)
)
);
New Way
$email = $email
|> fn($e) => filter_var($e, FILTER_SANITIZE_EMAIL)
|> trim(...)
|> strtolower(...);
Real-World Example 2: Array Transformations
Old Way
$numbers = [1, 2, 3, 4, 5];
$result = array_sum(
array_map(
fn($n) => $n * 2,
$numbers
)
);
New Way
$result = $numbers
|> fn($arr) => array_map(fn($n) => $n * 2, $arr)
|> array_sum(...);
Real-World Example 3: JSON API Processing
Old Way
$data = json_decode($json, true);
$data = array_filter($data);
$data = array_values($data);
New Way
$data = $json
|> fn($j) => json_decode($j, true)
|> array_filter(...)
|> array_values(...);
Laravel Examples: Old Way vs New Way
Laravel developers already enjoy fluent, chainable Collection and Eloquent APIs. The pipe operator shines specifically when mixing Collections with plain PHP functions, or when processing request data.
Example 1: Collection Output → PHP Function
Old Laravel Way
$json = json_encode(
User::all()
->where('active', true)
->pluck('email')
->toArray()
);
New Way with Pipe Operator
$json = User::all()
->where('active', true)
->pluck('email')
->toArray()
|> json_encode(...);
Example 2: Cleaning Request Input
Old Laravel Way
$email = strtolower(
trim(
$request->input('email')
)
);
New Way
$email = $request->input('email')
|> trim(...)
|> strtolower(...);
Example 3: Formatting an API Response
Old Laravel Way
return response()->json(
array_values(
array_filter($users)
)
);
New Way
return $users
|> array_filter(...)
|> array_values(...)
|> fn($u) => response()->json($u);
Example 4: File Content Processing in a Service Class
Old Way
$content = file_get_contents($path);
$content = trim($content);
$content = strip_tags($content);
$content = strtolower($content);
New Way
$content = file_get_contents($path)
|> trim(...)
|> strip_tags(...)
|> strtolower(...);
Real-World Example: Order Analytics
A common reporting task — sum up the amount of all “paid” orders.
Old Way
$total = array_sum(
array_map(
fn($order) => $order['amount'],
array_filter(
$orders,
fn($order) => $order['status'] === 'paid'
)
)
);
New Way
$total = $orders
|> fn($o) => array_filter($o, fn($order) => $order['status'] === 'paid')
|> fn($o) => array_map(fn($order) => $order['amount'], $o)
|> array_sum(...);
Each transformation step is now isolated and easy to scan.
Key Benefits of the Pipe Operator
1. Better readability — Code reads top-to-bottom in the same order it executes, instead of inside-out.
2. Fewer temporary variables — No need for $data = step1($data); $data = step2($data); chains.
3. Reduced nesting — fn3(fn2(fn1($value))) becomes a flat, linear pipeline.
4. Encourages functional, reusable transformation functions — small single-purpose functions compose naturally:
function sanitize($value) {
return trim($value);
}
function normalize($value) {
return strtolower($value);
}
$email = $email
|> sanitize(...)
|> normalize(...);
5. Compiler optimizations — Pipe chains compile to opcodes similar to nested calls, and in some cases the compiler can optimize away temporary variables for memory and performance gains.
When NOT to Use the Pipe Operator
For object method chaining, Laravel Collections and Eloquent query builders already provide elegant fluent syntax:
User::query()
->where('active', true)
->orderBy('name')
->get();
Adding |> here adds no value — the pipe operator is best reserved for chaining standalone functions or mixing function calls with method-chain results, not for replacing object method chains that are already fluent.
A Note on Arrow Functions
Because of how the implementation captures arrow function bodies, wrapping inline arrow functions in parentheses is sometimes necessary to avoid ambiguity:
$result = $value |> (fn($x) => $x * 2)(...) |> strval(...);
Keep this in mind when piping into anonymous functions directly.
Final Thoughts
The PHP 8.5 pipe operator (|>) brings a long-requested functional programming feature to the language, reducing nested function calls and creating natural, linear data pipelines. For Laravel developers, it’s especially useful for request sanitization, API response formatting, and bridging Collection output with native PHP functions.
It won’t replace Eloquent or Collection chaining — but for transformation-heavy code, it’s likely to become one of the most-used additions since arrow functions and the nullsafe operator.