PHP’s release cycle keeps delivering genuinely useful language features. PHP 8.5, released in late 2025, brought the pipe operator. PHP 8.6, expected later in 2026, adds clone-with expressions and partial function application. These are not academic curiosities—they change how you structure everyday code.
The pipe operator
The pipe operator (|>) takes the result of the left-hand expression and passes it as the single argument to the right-hand callable. That is all it does. But the effect on readability is significant when you have chains of transformations.
Before pipes
1 | $result = htmlspecialchars( |
You read this inside-out: trim first, then lowercase, then escape. The execution order is the reverse of the reading order.
With pipes
1 | $result = $userInput |
Now you read top-to-bottom, left-to-right. Each step is clear. The pipe operator passes the previous result as the first argument to the next function.
How it actually works
The pipe operator is syntactic sugar. $x |> foo(...) is equivalent to foo($x). The right-hand side must be a callable that accepts at least one argument. The left-hand result becomes that first argument.
1 | // These are equivalent |
Practical use cases
Data transformation pipelines:
1 | $cleaned = $rawCsvRow |
Wait—this is where it gets nuanced. The pipe operator passes the result as the first argument. For functions like array_map where the callback is the first argument and the array is second, you need a wrapper:
1 | function mapTrim(array $items): array { |
This is the pipe operator’s main limitation: it only fills the first parameter slot. Functions with the “data” parameter in any other position need wrappers or partial application (coming in 8.6).
Laravel collection alternative for simple cases:
1 | // Instead of creating a Collection just to chain |
In practice, Laravel’s Collection is still better for complex chains. Pipes shine for simple, sequential transformations.
Clone-with expressions
PHP 8.6 introduces a cleaner syntax for cloning objects with modified properties. This is particularly important for value objects and DTOs with readonly properties.
The problem
1 | readonly class Money |
You had to add a with method manually:
1 | readonly class Money |
Clone-with syntax
1 | $discounted = clone $price with {amount: 900}; |
This creates a clone of $price and overrides the amount property during cloning. It works with readonly properties because the assignment happens during the clone operation, before the object is fully constructed.
1 | // Multiple properties |
Why this matters for PHP
Immutable value objects are a cornerstone of domain-driven design, and PHP’s readonly properties (introduced in 8.1, expanded in 8.2) made them easier to create. But modifying them required verbose boilerplate. Clone-with removes that friction.
1 | readonly class ApiRequest |
Partial function application
Also expected in PHP 8.6, partial function application lets you fix some arguments of a function and get back a new callable with fewer parameters.
1 | // Fix the first argument of str_contains |
The ? placeholder marks which argument remains open. The result is a Closure that accepts the remaining arguments.
Combining with pipes
This is where partial application and the pipe operator become genuinely powerful together:
1 | $processedNames = $rawNames |
Each step receives the result from the previous one through the ? placeholder. This solves the pipe operator’s argument-position problem without wrapper functions.
Real-world example
1 | // A data processing pipeline |
Common mistakes with these features
Overusing pipes for readability that is not actually better
1 | // This is worse than the direct call |
Pipes add value when you have three or more chained transformations. For single calls, they add noise.
Forgetting clone-with creates a shallow copy
1 | readonly class Config |
Clone-with does not perform deep cloning. Nested objects are still shared references. Implement __clone() if you need deep copies.
Using partial application where a simple closure is clearer
1 | // Partial application |
If your team is not yet familiar with partial application syntax, a named closure with a descriptive variable name communicates intent better.
Production tradeoffs
Adoption pace: Do not rewrite existing code to use pipes everywhere. Introduce them in new code and let the codebase migrate naturally.
CI requirements: You need PHP 8.5+ across all environments. If you are still supporting PHP 8.1 or 8.2 in production, these features are off the table.
IDE support: PhpStorm and VS Code with Intelephense both support pipe operator syntax as of early 2026. Check your specific version.
Performance: The pipe operator compiles to the same opcodes as nested function calls. There is no runtime overhead. Clone-with is similarly zero-cost compared to manual cloning.
FAQ
Can I use the pipe operator with methods, not just functions?
Not directly. $obj |> $obj->method(...) does not work. You need to wrap the method call: $obj |> fn($x) => $x->transform() or use first-class callable syntax on a static method.
Does clone-with work with non-readonly classes?
Yes, but it is most useful with readonly properties since those cannot be modified after construction without it.
When should I use partial application vs. arrow functions?
Use partial application when you are genuinely fixing arguments of an existing function. Use arrow functions when you are building new logic that happens to wrap a function call.
Next steps
Start by enabling PHP 8.5 in your development environment and experimenting with the pipe operator on string processing functions. It is the least disruptive introduction point. Clone-with and partial application, when they land in 8.6, will compound the benefit.
If you are working with older PHP patterns, the PDO prepared statements guide shows the kind of structured database code that benefits from these modern language features. The AI-assisted PHP development guide covers how tools like Copilot handle these new syntax features.