Hi internals,
I'd like to open discussion on my (first!) RFC for the pipe assignment operator (|>=):
https://wiki.php.net/rfc/pipe_assignment_operator
It adds a compound assignment form of the pipe operator, so that
$x |>= callable is shorthand for $x = $x |> callable, with
support for chaining. Implementation with tests is at:
https://github.com/php/php-src/pull/22633
Looking forward to your feedback.
Thanks!
Caleb
Hi
I'd like to open discussion on my (first!) RFC for the pipe assignment
operator (|>=):
https://wiki.php.net/rfc/pipe_assignment_operatorIt adds a compound assignment form of the pipe operator, so that
$x |>= callable is shorthand for $x = $x |> callable, with
support for chaining. Implementation with tests is at:
https://github.com/php/php-src/pull/22633
Quick note regarding formalities: The voting widget was missing the
“Abstain” option, which I just added for you.
I haven't yet looked at the RFC contents.
Best regards
Tim Düsterhus
Quick note regarding formalities: The voting widget was missing the
“Abstain” option, which I just added for you.
Ah thanks! I just modified the template though, so that probably needs to be updated as well.
Caleb
Hi
Ah thanks! I just modified the template though, so that probably needs
to be updated as well.
It's already in the template at
https://wiki.php.net/rfc/template#voting_choices (since 2025-08-31, when
the “Abstain” RFC passed). Unsure what happened, the rest of your RFC
seems to match the current version of the template, particularly the
“RFC Impact” section which also got recent updates.
Best regards
Tim Düsterhus
It's already in the template at
https://wiki.php.net/rfc/template#voting_choices (since 2025-08-31, when
the “Abstain” RFC passed). Unsure what happened, the rest of your RFC
seems to match the current version of the template, particularly the
“RFC Impact” section which also got recent updates.
Hmm, not sure---could have accidentally deleted the line in Neovim
prior to copy/pasting. Thanks again for catching that!
Best,
Caleb
Ooooh, fun. Can we informally call |>= the "volcano operator" (like ?: is
the Elvis operator)?
...if only Hershey's Kisses had two paper strips coming out of the top.
mickmackusa
Ooooh, fun. Can we informally call |>= the "volcano operator" (like ?: is
the Elvis operator)?...if only Hershey's Kisses had two paper strips coming out of the top.
mickmackusa
I like to think of |> as the volcano operator, while |>= is the erupting
volcano operator.
;-)
Cheers,
Ben
I won’t get to vote on this RFC, but I wanted to give my brief opinion. To be fair, my initial opinion was that I loved the symmetry of this along with +=, -=, and similar operators, but really hated how I assumed it was likely be used. I started typing up a message showing examples of how it could be used, but as I did I fell in love with it.
It’s a little annoying to type on the standard US Keyboard layout, but its readable as a syntax and has a clear meaning once understood. This is the example that made me really love the <<Exploding Volcano>> operator (with PFA):
$array |>= array_map(transform(…), …);
Holly
Hi
I'd like to open discussion on my (first!) RFC for the pipe assignment
operator (|>=):
https://wiki.php.net/rfc/pipe_assignment_operator
I've given the RFC a read now and have the following comments:
Conceptionally I like the idea of having an “in-place modification
operator” for function calls and the semantics of the operator seem to
be consistent with the existing “modify-assign” operators we have,
particularly also with regard to operand order. Nice idea!
I appreciate how detailed the RFC describes that the feature will just
“work as expected” (e.g. with regard to variables targets or callable
styles), this is good to avoid any ambiguity.
The only thing I'm missing for the semantics is an explicit explanation
of the operator precedence and associativity (it has the same precedence
and associativity as any other assignment operator; but this needs to be
in the RFC). And please also include explicit examples along the lines
of:
If you write $foo |>= bar(...) |> baz(...) it will be interpreted as
if you have written $foo = (($foo |> bar(...)) |> baz(...)) with the
very explicit redundant parentheses.
Please also include some additional more complex examples, e.g. $foo |>= $bar |>= …, $foo += $bar |>= … and similar to make sure there is
no ambiguity for possible use cases that users might have.
For the examples, I'd like to note that some of the “before” examples
are needlessly complex and might not fairly represent the old code.
Specifically:
$input = $input |> trim(...) |> strtolower(...);
$this->currentOrder->lineItems = $this->currentOrder->lineItems
|> array_unique(...)
|> array_values(...)
|> array_reverse(...);
could already be:
$input = trim($input) |> strtolower(...);
$this->currentOrder->lineItems =
array_unique($this->currentOrder->lineItems)
|> array_values(...)
|> array_reverse(...);
Best regards
Tim Düsterhus
Conceptionally I like the idea of having an “in-place modification
operator” for function calls and the semantics of the operator seem to
be consistent with the existing “modify-assign” operators we have,
particularly also with regard to operand order. Nice idea!
Thanks! I'm glad others think so as well :).
I appreciate how detailed the RFC describes that the feature will just
“work as expected” (e.g. with regard to variables targets or callable
styles), this is good to avoid any ambiguity.
Thanks again, trying to make it as clear as possible.
The only thing I'm missing for the semantics is an explicit explanation
of the operator precedence and associativity (it has the same precedence
and associativity as any other assignment operator; but this needs to be
in the RFC). And please also include explicit examples along the lines
of:If you write
$foo |>= bar(...) |> baz(...)it will be interpreted as
if you have written$foo = (($foo |> bar(...)) |> baz(...))with the
very explicit redundant parentheses.Please also include some additional more complex examples, e.g.
$foo |>= $bar |>= …,$foo += $bar |>= …and similar to make sure there is
no ambiguity for possible use cases that users might have.
I've added a section in the RFC for this and included more complex examples.
For the examples, I'd like to note that some of the “before” examples
are needlessly complex and might not fairly represent the old code.
Specifically:$input = $input |> trim(...) |> strtolower(...); $this->currentOrder->lineItems = $this->currentOrder->lineItems |> array_unique(...) |> array_values(...) |> array_reverse(...);could already be:
$input = trim($input) |> strtolower(...); $this->currentOrder->lineItems =array_unique($this->currentOrder->lineItems)
|> array_values(...)
|> array_reverse(...);
I've cleaned up the examples to make them more representative of
existing code.
Best,
Caleb
Hi
The only thing I'm missing for the semantics is an explicit
explanation
of the operator precedence and associativity (it has the same
precedence
and associativity as any other assignment operator; but this needs to
be
in the RFC). And please also include explicit examples along the lines
of:If you write
$foo |>= bar(...) |> baz(...)it will be interpreted as
if you have written$foo = (($foo |> bar(...)) |> baz(...))with the
very explicit redundant parentheses.Please also include some additional more complex examples, e.g.
$foo |>= $bar |>= …,$foo += $bar |>= …and similar to make sure there
is
no ambiguity for possible use cases that users might have.I've added a section in the RFC for this and included more complex
examples.
Thank you. One note regarding “the lowest precedence level,
right-associative”. This is not quite correct. While the assignment
operators have fairly low precedence, they are not the lowest. As an
example, the infamous $foo = bar() or die()`` pattern relies on or
having a lower precedence than assignment. This should be corrected.
The $result = ($x |>= double(...)) |> triple(...); example also
doesn't showcase precedence, because of the explicit parentheses.
Looking at the RFC examples again, I was reminded of this RFC:
https://wiki.php.net/rfc/implicit_move_optimisation, which concerns
itself with optimizing the $foo = func($foo); case. Perhaps it makes
sense to list this in the references section, because with |>= this
“in-place” reassignment would become an official pattern.
Best regards
Tim Düsterhus
Thank you. One note regarding “the lowest precedence level,
right-associative”. This is not quite correct. While the assignment
operators have fairly low precedence, they are not the lowest. As an
example, the infamous$foo = bar() ordie()`` pattern relies onor
having a lower precedence than assignment. This should be corrected.The
$result = ($x |>= double(...)) |> triple(...);example also
doesn't showcase precedence, because of the explicit parentheses.
Ah, yes. I meant among the symbolic operators but you are correct and I've
updated to make this more clear. I removed the explicit parentheses from the
example.
Looking at the RFC examples again, I was reminded of this RFC:
https://wiki.php.net/rfc/implicit_move_optimisation, which concerns
itself with optimizing the$foo = func($foo);case. Perhaps it makes
sense to list this in the references section, because with|>=this
“in-place” reassignment would become an official pattern.
I've added this to the references and discussed it in the Future Scope
section.
Best,
Caleb
Hi
Thank you. One note regarding “the lowest precedence level,
right-associative”. This is not quite correct. While the assignment
operators have fairly low precedence, they are not the lowest. As an
example, the infamous$foo = bar() ordie()`` pattern relies onor
having a lower precedence than assignment. This should be corrected.The
$result = ($x |>= double(...)) |> triple(...);example also
doesn't showcase precedence, because of the explicit parentheses.Ah, yes. I meant among the symbolic operators but you are correct and I've
updated to make this more clear. I removed the explicit parentheses from the
example.
Thank you, the precedence section LGTM now. And overall I don't have any
further comments regarding the contents of the RFC.
Best regards
Tim Düsterhus
Thank you, the precedence section LGTM now. And overall I don't have any
further comments regarding the contents of the RFC.Best regards
Tim Düsterhus
Awesome! Thank you sir for all your feedback and help!
Best,
Caleb
Hi internals,
I'd like to open discussion on my (first!) RFC for the pipe assignment
operator (|>=):
https://wiki.php.net/rfc/pipe_assignment_operatorIt adds a compound assignment form of the pipe operator, so that
$x |>= callable is shorthand for $x = $x |> callable, with
support for chaining. Implementation with tests is at:
https://github.com/php/php-src/pull/22633Looking forward to your feedback.
Thanks!
Caleb
Perhaps weirdly, I am not a huge fan of this RFC. I'm open to pipe-compound operators (the other that's been suggested is a null-safe ?|>, which I'd support), but I'm not sure of the use case for this one.
That may be because, from a functional programming point of view, piping a back to itself makes little if any sense. Values should be immutable, so you would be doing
$b = $a |> foo(...) |> bar(...) |> baz(...);
I cannot think of a case where I would want to put $a on the left side, too. How realistic is this use case?
I don't think this RFC would cause any harm, I suppose, so I probably won't vote against it. But at the moment I don't see a compelling reason to vote for it. A concrete real-world use case would help make that case, because I cannot come up with one myself.
--Larry Garfield
Hi internals,
I'd like to open discussion on my (first!) RFC for the pipe assignment
operator (|>=):
https://wiki.php.net/rfc/pipe_assignment_operatorIt adds a compound assignment form of the pipe operator, so that
$x |>= callable is shorthand for $x = $x |> callable, with
support for chaining. Implementation with tests is at:
https://github.com/php/php-src/pull/22633Looking forward to your feedback.
Thanks!
Caleb
Perhaps weirdly, I am not a huge fan of this RFC. I'm open to pipe-compound operators (the other that's been suggested is a null-safe ?|>, which I'd support), but I'm not sure of the use case for this one.That may be because, from a functional programming point of view, piping a back to itself makes little if any sense. Values should be immutable, so you would be doing
$b = $a |> foo(...) |> bar(...) |> baz(...);
I cannot think of a case where I would want to put $a on the left side, too. How realistic is this use case?
I don't think this RFC would cause any harm, I suppose, so I probably won't vote against it. But at the moment I don't see a compelling reason to vote for it. A concrete real-world use case would help make that case, because I cannot come up with one myself.
--Larry Garfield
Hey Larry,
// before
public function makeSlug(string $value): string {
$value = $value |> mb_strtolower(...); // ...
$number = $this->getNextSlugNumber($value); // checks DB
if (0 < $number) { $value .= "-$number"; }
return $value;
}
// after
public function makeSlug(string $value): string {
$value |>= mb_strtolower(...) ; // ...
$number = $this->getNextSlugNumber($value); // checks DB
if (0 < $number) { $value .= "-$number"; }
return $value;
}
Currently we have to make assignment gymnastics even for use cases that
do not require an immutable second value. Would argue many people in PHP
do and will use pipes for readability, not because they suddenly write
PHP from a functional programming point of view. This is a good
proposal, IMO.
--
Cheers
Nick
Hi Nick,
// before
public function makeSlug(string $value): string {
$value = $value |> mb_strtolower(...); // ...
$number = $this->getNextSlugNumber($value); // checks DB
if (0 < $number) { $value .= "-$number"; }
return $value;
}// after
public function makeSlug(string $value): string {
$value |>= mb_strtolower(...) ; // ...
$number = $this->getNextSlugNumber($value); // checks DB
if (0 < $number) { $value .= "-$number"; }
return $value;
}Currently we have to make assignment gymnastics even for use cases that
do not require an immutable second value. Would argue many people in PHP
do and will use pipes for readability, not because they suddenly write
PHP from a functional programming point of view. This is a good
proposal, IMO.
I would argue that is a very bad practice in php, to alter the actual
function parameter variable. That is because any stack trace obtained will
not reflect the initial value but the modified value.
And generally, it is a bad practice to override a variable with some other
value that represents something different. You could have had
incrementally: $lowercaseValue, and $slug/$valueWithSlugNumber.
--
Alex
I would argue that is a very bad practice in php, to alter the actual function parameter variable. That is because any stack trace obtained will not reflect the initial value but the modified value.
And generally, it is a bad practice to override a variable with some other value that represents something different. You could have had incrementally: $lowercaseValue, and $slug/$valueWithSlugNumber.
While I agree, we need to accept that often people do not use the best practices when coding. PHP makes the barrier to entry low, which invites people who are still learning what best practices are.
I wanted to argue against this for exactly this reason, but it’s really not that bad. When combined with FCC, PFA, and pipe chaining, it can really condense code.
My only hesitation is that what we’re going to end up with is a lot of:
$foo |>= a(…)
$foo |>= b(…)
$foo |>= c(…)
This completely defeats the spirit of this operation (and probably has terrible performance).
Holly
Hi everyone, thanks for the feedback.
Perhaps weirdly, I am not a huge fan of this RFC. I'm open to pipe-compound operators (the
other that's been suggested is a null-safe ?|>, which I'd support), but I'm not sure of the
use case for this one.That may be because, from a functional programming point of view, piping a back to itself makes
little if any sense. Values should be immutable, so you would be doing$b = $a |> foo(...) |> bar(...) |> baz(...);
I cannot think of a case where I would want to put $a on the left side, too. How realistic is this
use case?I don't think this RFC would cause any harm, I suppose, so I probably won't vote against
it. But at the moment I don't see a compelling reason to vote for it. A concrete real-world
use case would help make that case, because I cannot come up with one myself.--Larry Garfield
I understand the FP perspective, but PHP isn't an immutable language.
We mutate variables constantly; that's why +=, .=, and ??= exist.
The motivation for this RFC came from seeing this pattern and wishing
that such an operator existed.
Here are patterns from a production codebase:
Property self-assignment with filter + reindex:
// before: $this->personnel repeated
$this->personnel = array_values(array_filter(
$this->personnel,
fn ($u) => ($u['id'] ?? null) !== $userId,
));
// after: appears once
$this->personnel
|>= array_filter(?, fn ($u) => ($u['id'] ?? null) !== $userId)
|> array_values(...);
Here's another common Laravel pattern (real example from codebase),
wrapping a variable in collect() to transform it, then converting back
with ->all():
$filters = collect($filters)
->map(function ($value) {
// logic...
})
->all();
At its core this is just $filters = transform($filters). People
already reach for this self-assignment pattern constantly; collections
just provide the fluent API for the transformation. With |>= and
native array functions you get the same fluency without the round-trip:
$filters |>= some_transform(...);
Even simple $x = func($x) calls benefit; the variable doesn't need
to be duplicated on both sides:
// all real patterns from one codebase
$post_data = json_decode($post_data, true);
$dates = array_reverse($dates);
$model = ltrim($model, '\\/');
$items = array_slice($items, $offset, $per_page);
$formData['search']['name'] = str_replace('\\', '', $formData['search']['name']);
// become
$post_data |>= json_decode(?, true);
$dates |>= array_reverse(...);
$model |>= ltrim(?, '\\/');
$items |>= array_slice(?, $offset, $per_page);
$formData['search']['name'] |>= str_replace('\\', '', ?);
Here's another production example (not the nicest code but you get the
point), it's much cleaner using |>= than repeating the expression:
// before
$params['current']['pallet_quantity'] = intval($params['current']['pallet_quantity']);
$params['current']['pallet_cost'] = floatval($params['current']['pallet_cost']);
$params['current']['box_quantity'] = intval($params['current']['box_quantity']);
$params['current']['cox_cost'] = floatval($params['current']['box_cost']);
$params['current']['cogs'] = floatval($params['current']['cogs']);
// after
$params['current']['pallet_quantity'] |>= intval(...);
$params['current']['pallet_cost'] |>= floatval(...);
$params['current']['box_quantity'] |>= intval(...);
$params['current']['cox_cost'] |>= floatval(...);
$params['current']['cogs'] |>= floatval(...);
This is the same argument as .=; nobody writes $x = $x . ' suffix'
anymore. The benefit scales with variable complexity.
Sequential transforms in business logic also clean up nicely with PFA:
// from real codebase
$model = ltrim($model, '\\/');
$model = str_replace('/', '\\', $model);
// becomes a single expression
$model |>= ltrim(?, '\\/') |> str_replace('/', '\\', ?);
The consistency argument is also worth noting. Every binary operator
where in-place transformation makes sense has a compound assignment
form. We accepted |> as a first-class operator; its compound form
follows the same pattern as +=, .=, ??=, etc.
Hey Larry,
// before
public function makeSlug(string $value): string {
$value = $value |> mb_strtolower(...); // ...
$number = $this->getNextSlugNumber($value); // checks DB
if (0 < $number) { $value .= "-$number"; }
return $value;
}// after
public function makeSlug(string $value): string {
$value |>= mb_strtolower(...) ; // ...
$number = $this->getNextSlugNumber($value); // checks DB
if (0 < $number) { $value .= "-$number"; }
return $value;
}Currently we have to make assignment gymnastics even for use cases that
do not require an immutable second value. Would argue many people in PHP
do and will use pipes for readability, not because they suddenly write
PHP from a functional programming point of view.Nick
Well said, Nick. Exactly this, pipes are a readability tool in PHP,
not a signal that we're writing pure FP like Haskell.
This is a good proposal, IMO.
Thank you! That means a lot.
I would argue that is a very bad practice in php, to alter the actual
function parameter variable. That is because any stack trace obtained will
not reflect the initial value but the modified value.And generally, it is a bad practice to override a variable with some other
value that represents something different. You could have had
incrementally: $lowercaseValue, and $slug/$valueWithSlugNumber.Alex
I wouldn't call it "very bad practice", it may not be the "best" practice
but it is still extremely common in PHP codebases and the language has
never discouraged it. We're not the parameter reassignment police 🙃.
That said, |>= isn't even limited to parameters; it works on
properties, array dimensions, and locals.
$this->message |>= trim(...);
That's the same pattern as $this->count += 1. The type and semantic
meaning don't change; it's the same data, transformed.
PHP already has $x .= ' suffix' instead of requiring
$suffixedX = $x . ' suffix'. Nobody argues .= encourages bad
practice. |>= is the same pattern; a transformation, not a
replacement with something semantically different.
Using different variable names ($lowercaseValue, $slug) is a valid
stylistic/preference choice. But in practice, people reuse variables for
sequential transforms, and |>= just makes that existing pattern cleaner.
While I agree, we need to accept that often people do not use the best
practices when coding. PHP makes the barrier to entry low, which invites
people who are still learning what best practices are.I wanted to argue against this for exactly this reason, but it's really
not that bad. When combined with FCC, PFA, and pipe chaining, it can
really condense code.Holly
Agreed! The more I've played around with this the more I've come to love
how expressive and concise it is.
My only hesitation is that what we're going to end up with is a lot of:
$foo |>= a(…) $foo |>= b(…) $foo |>= c(…)This completely defeats the spirit of this operation (and probably has
terrible performance).
Even if folks do choose to write it that way then I would argue
that it is still cleaner than:
$foo = a($foo);
$foo = b($foo);
$foo = c($foo);
But I think the operator naturally encourages piping, so I don't think it
will be too much of an issue:
$foo |>= a(...) |> b(...) |> c(...);
Now I imagine that you will (potentially) see a lot of regular function
/ method calls using this to avoid having to repeat the variable
expression:
// before
$someVeryLongVariableName = array_values($someVeryLongVariableName);
// after
$someVeryLongVariableName |>= array_values(...);
On the performance note, there should be zero overhead. Each |>= compiles
to the exact same opcodes as $x = $x |> ...; there is no difference.
For complex LHS expressions like the following, |>= is actually
more performant (because it evaluates sub-expressions once instead of
twice, same memoization mechanism as ??=) and more concise (how do you
beat that?):
//before
$array[$this->computeKey($object)] = strtolower($array[$this->computeKey($object)]);
// or you introduce a temp var
$key = $this->computeKey($object);
$array[$key] = strtolower($array[$key]);
// after: performant and concise without having to use temp var
$array[$this->computeKey($object)] |>= strtolower(...);
Best,
Caleb
Let me try to rephrase Larry's idea.
The pipe operator made its way into PHP from functional programming
languages, where immutability is a key aspect of the language's
behavior. In those languages, it enables code that is both more
productive and freer from side effects.
The goal of bringing such operators into PHP is to enhance the
language's predictability and minimize side effects, gradually shifting
the coding style from imperative to more functional—rather than simply
providing a bit of convenient syntactic sugar.
Attempting to transform such an operator from an immutable, functional
construct into a mutable, imperative one steers the language in the
wrong direction and undoes previous efforts.
Therefore, the ability to simplify the expression
$params['current']['pallet_cost'] = floatval($params['current']['pallet_cost']) does not actually improve
this code. This code and other examples are initially designed to mutate
the original array rather than returning a new one with corrected types.
It also uses floatval/intval instead of the faster native type casts
(float)/(int). If you rewrite this code using native casts, the pipe
won't be applicable to this case at all.
You’re pointing to the Laravel experience. But in Laravel, most
operations involving collections (with the exception of transform,
where it is explicitly stated otherwise) and arrays (using the Arr
helper) are actually performed immutably. Those helpers for immutability
and method chaining were introduced in Laravel a long time ago precisely
because the language lacked convenient built-in tools for such tasks.
If you want mutability, you can always intoroduce a helper in a specific
project.
function apply(&$value, callable $callback) {
return $value = $callback($value);
}
аnd call
apply($params['current']['pallet_cost'], floatval(...));
You also cite the example $model |>= ltrim(?) and compare it to $x .= 'yyy', but the scenarios are different. In $x .= 'yyy', the
right-hand side doesn't depend on $x, so there’s no cognitive
overhead. In $model |>= ltrim(?), however, the right-hand side depends
on the variable from the left via the ? placeholder, creating a
mind-bending circular dependency. $model goes into ltrim and then
comes back out; that is far more convoluted than simply appending to a
string or incrementing/decrementing a value. That is likely why
assignment operators like .=, +=, and -= are used much more
frequently than others—they are easier to grasp than an operation like
$b %= $a.
Why do you see $filters = collect($filters)->map()->all(); in Laravel
project code more often than transform($filters)? Because developers
also write in JavaScript, which lacks a transform method.
Consequently, the map logic is more familiar to them, as it behaves
predictably in both languages. And why doesn't JavaScript have a similar
transform method? Because it can lead to unpredictable side effects.
For example, if a handler accesses not only the current element but the
entire collection as well, it is completely unclear whether the handler
for the second element will see the first element in its modified state
or its original one. The approach involving an immutable map and
assignment after the entire array has been processed creates more
predictable behavior. It is precisely this immutability of the source
array that allows certain languages to process elements within a map
in parallel or employ other optimizations without the risk of side
effects or race conditions. If I understand correctly, Larry wants the
language to move in precisely this direction.
18.07.2026 3:01, Caleb White пишет:
Hi everyone, thanks for the feedback.
Perhaps weirdly, I am not a huge fan of this RFC. I'm open to pipe-compound operators (the
other that's been suggested is a null-safe ?|>, which I'd support), but I'm not sure of the
use case for this one.That may be because, from a functional programming point of view, piping a back to itself makes
little if any sense. Values should be immutable, so you would be doing$b = $a |> foo(...) |> bar(...) |> baz(...);
I cannot think of a case where I would want to put $a on the left side, too. How realistic is this
use case?I don't think this RFC would cause any harm, I suppose, so I probably won't vote against
it. But at the moment I don't see a compelling reason to vote for it. A concrete real-world
use case would help make that case, because I cannot come up with one myself.--Larry Garfield
I understand the FP perspective, but PHP isn't an immutable language.
We mutate variables constantly; that's why+=,.=, and??=exist.
The motivation for this RFC came from seeing this pattern and wishing
that such an operator existed.
--
Vadim Dvorovenko
Let me try to rephrase Larry's idea.
The pipe operator made its way into PHP from functional programming
languages, where immutability is a key aspect of the language's
behavior. In those languages, it enables code that is both more
productive and freer from side effects.The goal of bringing such operators into PHP is to enhance the
language's predictability and minimize side effects, gradually shifting
the coding style from imperative to more functional—rather than simply
providing a bit of convenient syntactic sugar.Attempting to transform such an operator from an immutable, functional
construct into a mutable, imperative one steers the language in the
wrong direction and undoes previous efforts.Therefore, the ability to simplify the expression
$params['current']['pallet_cost'] = floatval($params['current']['pallet_cost'])does not actually improve
this code. This code and other examples are initially designed to mutate
the original array rather than returning a new one with corrected types.
It also usesfloatval/intvalinstead of the faster native type casts
(float)/(int). If you rewrite this code using native casts, the pipe
won't be applicable to this case at all.You’re pointing to the Laravel experience. But in Laravel, most
operations involving collections (with the exception oftransform,
where it is explicitly stated otherwise) and arrays (using theArr
helper) are actually performed immutably. Those helpers for immutability
and method chaining were introduced in Laravel a long time ago precisely
because the language lacked convenient built-in tools for such tasks.If you want mutability, you can always intoroduce a helper in a specific
project.function apply(&$value, callable $callback) { return $value = $callback($value); }аnd call
apply($params['current']['pallet_cost'], floatval(...));You also cite the example
$model |>= ltrim(?)and compare it to$x .= 'yyy', but the scenarios are different. In$x .= 'yyy', the
right-hand side doesn't depend on$x, so there’s no cognitive
overhead. In$model |>= ltrim(?), however, the right-hand side depends
on the variable from the left via the?placeholder, creating a
mind-bending circular dependency.$modelgoes intoltrimand then
comes back out; that is far more convoluted than simply appending to a
string or incrementing/decrementing a value. That is likely why
assignment operators like.=,+=, and-=are used much more
frequently than others—they are easier to grasp than an operation like
$b %= $a.Why do you see
$filters = collect($filters)->map()->all();in Laravel
project code more often thantransform($filters)? Because developers
also write in JavaScript, which lacks atransformmethod.
Consequently, themaplogic is more familiar to them, as it behaves
predictably in both languages. And why doesn't JavaScript have a similar
transformmethod? Because it can lead to unpredictable side effects.
For example, if a handler accesses not only the current element but the
entire collection as well, it is completely unclear whether the handler
for the second element will see the first element in its modified state
or its original one. The approach involving an immutable map and
assignment after the entire array has been processed creates more
predictable behavior. It is precisely this immutability of the source
array that allows certain languages to process elements within a map
in parallel or employ other optimizations without the risk of side
effects or race conditions. If I understand correctly, Larry wants the
language to move in precisely this direction.
Impressively, I think this explanation stated my position better than I could. :-) Yes, I am in favor of pushing PHP in a more-functional, mostly-immutable direction (without going all the way to pathological purity like in Haskell). A variant of pipe that is intrinsically built on mutable variables goes against the intent. Yes, PHP is not an inherently immutable language today, but you can easily use it that way if you're careful and know where the edges are where you shouldn't.
I think the above description has actually pushed me over into the No category on this RFC. (Which doesn't mean I'm necessarily in favor of the alternate |>= proposal. I'm still pondering that one.)
I do agree that some longer-term planning around what alternate pipe forms make sense is wise, and a conversation I'm open to having. But not for a few weeks, as we should be focused on 8.6 at the moment, and none of these will make it into 8.6.
--Larry Garfield
Hi
Impressively, I think this explanation stated my position better than I
could. :-) Yes, I am in favor of pushing PHP in a more-functional,
mostly-immutable direction (without going all the way to pathological
purity like in Haskell). A variant of pipe that is intrinsically built
on mutable variables goes against the intent. Yes, PHP is not an
inherently immutable language today, but you can easily use it that way
if you're careful and know where the edges are where you shouldn't.
Nothing about |> is unique to functional programming or immutability,
it's just another way of writing a function call. I disagree with trying
to academically gatekeep functionality that is entirely consistent with
PHP’s current semantics in an attempt to push PHP into any specific
paradigm, particularly when it’s a paradigm that does not match how a
majority of PHP code is written in practice.
With regard to “you shouldn't modify variables in-place”, I'd like to
note that Rust, a language where variables are immutable by default,
supports reassigning a variable to be of a different type in spirit by
redeclaring and thus shadowing the previous variable. In some cases this
is even necessary to satisfy the borrow checker. Of course, PHP doesn’t
come with the technical consideration of a borrow checker, but
incrementally refining a value is nevertheless a common pattern -
something I also do in Rust, even when not technically required - and I
find that the RFC makes a good example with the “Sequential Processing”
(https://wiki.php.net/rfc/pipe_assignment_operator#sequential_processing).
and none of these will make it into 8.6.
This is false: The featured RFC had its last change on July 14th (which
I consider to be a minor change), and the last major change on July,
13th. This means it may open voting starting July 27th, ending August
10th and meeting the soft freeze deadline. Even if we consider the
change on the 14th to be a major change, it may (barely) meet the
deadline.
Best regards
Tim Düsterhus
Hey Caleb,
Am 20.07.2026 um 04:11 schrieb Larry Garfield larry@garfieldtech.com:
Impressively, I think this explanation stated my position better than I could. :-) Yes, I am in favor of pushing PHP in a more-functional, mostly-immutable direction (without going all the way to pathological purity like in Haskell). A variant of pipe that is intrinsically built on mutable variables goes against the intent. Yes, PHP is not an inherently immutable language today, but you can easily use it that way if you're careful and know where the edges are where you shouldn't.
I think the above description has actually pushed me over into the No category on this RFC. (Which doesn't mean I'm necessarily in favor of the alternate |>= proposal. I'm still pondering that one.)
I do agree that some longer-term planning around what alternate pipe forms make sense is wise, and a conversation I'm open to having. But not for a few weeks, as we should be focused on 8.6 at the moment, and none of these will make it into 8.6.
--Larry Garfield
sorry that you had to read this mail; Larry often has ideas that don't work well in practice - and then core devs have to shoot this down. Please just ignore this.
Bob
Hey Caleb,
Am 20.07.2026 um 04:11 schrieb Larry Garfield larry@garfieldtech.com:
Impressively, I think this explanation stated my position better than I could. :-) Yes, I am in favor of pushing PHP in a more-functional, mostly-immutable direction (without going all the way to pathological purity like in Haskell). A variant of pipe that is intrinsically built on mutable variables goes against the intent. Yes, PHP is not an inherently immutable language today, but you can easily use it that way if you're careful and know where the edges are where you shouldn't.
I think the above description has actually pushed me over into the No category on this RFC. (Which doesn't mean I'm necessarily in favor of the alternate |>= proposal. I'm still pondering that one.)
I do agree that some longer-term planning around what alternate pipe forms make sense is wise, and a conversation I'm open to having. But not for a few weeks, as we should be focused on 8.6 at the moment, and none of these will make it into 8.6.
--Larry Garfield
sorry that you had to read this mail; Larry often has ideas that don't
work well in practice - and then core devs have to shoot this down.
Please just ignore this.Bob
Bob, this is an extremely inappropriate email to send. All sorts of people disagree with all sorts of proposals for all sorts of reasons. All sorts of people "often have ideas that won't work well in practice." That's the whole point of a list discussion: To let those differences shake out and find the stuff that does work that people can agree on.
Singling out one person (who has been involved in several successful RFCs) and implying that person is some sort of idea-troll to be specifically ignored is grossly inappropriate, and I would expect better of someone of your stature.
--Larry Garfield
Hello, Caleb.
Firtly, i’d like to point out that you aren’t the first person to come
up with the idea of combining assignment and pipeline operators, and
inroduce |>= operator
Take a look at discussion, https://news-web.php.net/php.internals/128141
. RFC draft is here
https://github.com/vadimonus/php-rfc/blob/main/ltr-assignment.md.
I haven't submitted these drafts as an RFC yet because I haven't
received enough positive feedback on the first RFC in the chain:
https://wiki.php.net/rfc/pipe_to_return. You can see another drafts in
github.
The main idea, is that pipe operator reverses traditional funcation call
reading order, so we need some more operators with same order to use
together to reduce cognitive load.
Your variant of this operator makes traditional rigth to left action,
like other action. But |> arrow visually defines opposite direction.
This may lead to incorrect perception, increase cognitive load and lead
to mistakes.
I think, all extensions of pipe operator should be ducsussed together to
intorduce non conflicting group of operators. Please add to your RFC
links to other discussions and theese RFC drafts.
10.07.2026 11:45, Caleb White пишет:
Hi internals,
I'd like to open discussion on my (first!) RFC for the pipe assignment operator (|>=):
https://wiki.php.net/rfc/pipe_assignment_operatorIt adds a compound assignment form of the pipe operator, so that
$x |>= callable is shorthand for $x = $x |> callable, with
support for chaining. Implementation with tests is at:
https://github.com/php/php-src/pull/22633Looking forward to your feedback.
Thanks!
Caleb
--
Vadim Dvorovenko
Firtly, i'd like to point out that you aren't the first person to come
up with the idea of combining assignment and pipeline operators, and
inroduce|>=operatorTake a look at discussion,
https://news-web.php.net/php.internals/128141 . RFC draft is here
https://github.com/vadimonus/php-rfc/blob/main/ltr-assignment.md.I haven't submitted these drafts as an RFC yet because I haven't
received enough positive feedback on the first RFC in the chain:
https://wiki.php.net/rfc/pipe_to_return. You can see another drafts
in github.
Hi Vadim,
Thanks for the pointer, interesting to see that the idea of combining
assignment with the pipe operator has come up before. Great minds!
I did take a look at your pipe-to-return RFC and the LTR assignment
draft. These are fundamentally different proposals from what this RFC
does, though. Your |>= reverses assignment direction entirely
(expr |>= $var means $var = expr), whereas mine is a compound
assignment in the traditional sense ($var |>= callable means
$var = $var |> callable), the same pattern as +=, .=, and ??=.
The main idea, is that pipe operator reverses traditional funcation
call reading order, so we need some more operators with same order to
use together to reduce cognitive load.Your variant of this operator makes traditional rigth to left action,
like other action. But|>arrow visually defines opposite direction.
This may lead to incorrect perception, increase cognitive load and
lead to mistakes.
The scope is quite different. Your drafts introduce an entirely
new assignment direction for PHP along with a full family of LTR
compound operators (|> +=, |> -=, |> .=, etc.). That's a
significantly larger surface area change. I'd gently push back
on the premise that $result = expr |> f(...) |> g(...) "reverses
traditional function call reading order". Pipes don't reverse reading
order, they fix it; nested calls read inside-out (g(f(expr))), and
pipes linearize that left-to-right. Assignment on the left is just
how every C-family language works; nobody reads $result = 1 + 2
and feels a directional conflict. Every language with pipes
(F#, Elixir, OCaml, Hack) keeps var = expr |> ... and none of
them have introduced LTR assignment to complement it.
Even if those proposals were accepted, I think most PHP developers
would still reach for $var = expr out of habit and familiarity.
So |>= as a compound assignment operator would still have independent
value; it makes the very common $x = transform($x) pattern cleaner
regardless of whether LTR assignment exists.
I think, all extensions of pipe operator should be ducsussed together
to intorduce non conflicting group of operators. Please add to your
RFC links to other discussions and theese RFC drafts.
I don't think it makes sense to bundle these together or gate one on
the other. They solve different problems and can be evaluated on their
own merits. As for adding links to your drafts in my RFC, I'd prefer
to keep it focused on its own proposal. You're of course welcome to
cross-reference my RFC from your drafts if you'd like.
Best,
Caleb
Yes, I have carefully studied the RFCs and understand that they deal
with completely different syntax and use cases. However, both proposals
advocate for adding and using the |>= operator. Attempting to use it
for both scenarios would result in a grammar conflict (the case $x |>= $y must be interpreted unambiguously). Therefore, it is appropriate to
point out that this is not the only RFC proposing the |>= combination.
19.07.2026 11:54, Caleb White пишет:
Firtly, i'd like to point out that you aren't the first person to come
up with the idea of combining assignment and pipeline operators, and
inroduce|>=operatorTake a look at discussion,
https://news-web.php.net/php.internals/128141 . RFC draft is here
https://github.com/vadimonus/php-rfc/blob/main/ltr-assignment.md.I haven't submitted these drafts as an RFC yet because I haven't
received enough positive feedback on the first RFC in the chain:
https://wiki.php.net/rfc/pipe_to_return. You can see another drafts
in github.
Hi Vadim,Thanks for the pointer, interesting to see that the idea of combining
assignment with the pipe operator has come up before. Great minds!I did take a look at your pipe-to-return RFC and the LTR assignment
draft. These are fundamentally different proposals from what this RFC
does, though. Your|>=reverses assignment direction entirely
(expr |>= $varmeans$var = expr), whereas mine is a compound
assignment in the traditional sense ($var |>= callablemeans
$var = $var |> callable), the same pattern as+=,.=, and??=.The main idea, is that pipe operator reverses traditional funcation
call reading order, so we need some more operators with same order to
use together to reduce cognitive load.Your variant of this operator makes traditional rigth to left action,
like other action. But|>arrow visually defines opposite direction.
This may lead to incorrect perception, increase cognitive load and
lead to mistakes.
The scope is quite different. Your drafts introduce an entirely
new assignment direction for PHP along with a full family of LTR
compound operators (|> +=,|> -=,|> .=, etc.). That's a
significantly larger surface area change. I'd gently push back
on the premise that$result = expr |> f(...) |> g(...)"reverses
traditional function call reading order". Pipes don't reverse reading
order, they fix it; nested calls read inside-out (g(f(expr))), and
pipes linearize that left-to-right. Assignment on the left is just
how every C-family language works; nobody reads$result = 1 + 2
and feels a directional conflict. Every language with pipes
(F#, Elixir, OCaml, Hack) keepsvar = expr |> ...and none of
them have introduced LTR assignment to complement it.Even if those proposals were accepted, I think most PHP developers
would still reach for$var = exprout of habit and familiarity.
So|>=as a compound assignment operator would still have independent
value; it makes the very common$x = transform($x)pattern cleaner
regardless of whether LTR assignment exists.I think, all extensions of pipe operator should be ducsussed together
to intorduce non conflicting group of operators. Please add to your
RFC links to other discussions and theese RFC drafts.
I don't think it makes sense to bundle these together or gate one on
the other. They solve different problems and can be evaluated on their
own merits. As for adding links to your drafts in my RFC, I'd prefer
to keep it focused on its own proposal. You're of course welcome to
cross-reference my RFC from your drafts if you'd like.Best,
Caleb
--
Vadim Dvorovenko
Yes, I have carefully studied the RFCs and understand that they deal
with completely different syntax and use cases. However, both proposals
advocate for adding and using the|>=operator. Attempting to use it
for both scenarios would result in a grammar conflict (the case$x |>= $ymust be interpreted unambiguously). Therefore, it is appropriate to
point out that this is not the only RFC proposing the|>=combination.Vadim Dvorovenko
I see that you formally published your RFC yesterday---I'll link to it in my references.
Best,
Caleb
Hey Caleb,
Hi internals,
I'd like to open discussion on my (first!) RFC for the pipe assignment operator (|>=):
https://wiki.php.net/rfc/pipe_assignment_operatorIt adds a compound assignment form of the pipe operator, so that
$x |>= callable is shorthand for $x = $x |> callable, with
support for chaining. Implementation with tests is at:
https://github.com/php/php-src/pull/22633Looking forward to your feedback.
Thanks!
Caleb
Thanks for the RFC! As you already could guess I am in support. Been
running your implementation and didn't run into anything unexpected, nor
was I able to break it in different ways than the current pipe
behaviour. Though, I'd like to add the following.
- This was feeling nitpicky at first, but it doesn't leave me alone
since I first read your RFC. :) Now, given what Vadim added to the
discussion, I think it is worth bringing it up. Right now we are doing:
$someVar = $someVar |> array_filter(...);
the RFC allows to omit the noise:
$someVar = |> array_filter(...);
you see where I am going; now let's remove the white space:
$someVar =|> array_filter(...);
my point is: why |>= and not =|>?
I think the latter would be more intuitive: assign the result of piping
to the variable. I know that |>= follows the established foo=
convention for compound assignments like ??= or .=; which is an
argument in its favour. Still, I think =|> better communicates how
this particular operation expands. Especially when considering future
additions like the ones Vadim proposes in future scope.
Because a side effect of having =|> would be that the right hand side
of |> remains open to extension for potential in-pipe-behaviour
modifying features like the ones Vadim proposes -- without the final
assignment being affected. As in, =|> assigns the pipe result, while
=|>+, =|>-, =|> ., =|>whatever allow modifying in-pipe
behaviour. This would make sense because perhaps these pipe behaviour
operators will also be allowed for non-shorthand assigned (|>+, |> -, |> . ) pipes that want the resulting immutable right hand side
Larry made an argument for. Having a clear separation between
assignment, and potential future additions to modify pipe behaviour
makes sense. As in, want to add a modifying operator later? Cool, your
assignment remains in tact =|>. You just add a modifying operator
=|>- instead of flipping from |>= to |>-= which would affect final
assignment and in-pipe behaviour -- having the modifier out of the
final assignment decision is cleaner.
Also, it is not impossible that what Vadim proposes in future scope
would result in something like |>=??= which IMO makes an even stronger
point for strictly separating what is proposed here and potential future
additions of modifying operators: =|> .. |> ??=. Because these are
different: ... |> ??= (for in-pipe operations) and =|> ... |> ??=
(only for the final assignment). Vadims proposal makes sense on it's
own, but it currently mixes two concerns: in-pipe operations and final
assignment -- which I believe should be separated. Both of your
proposals (especially Vadims future scope) should probably rather
complement each other instead of competing; I think what I am writing
here potentially could make this easier.
One additional soft argument is that text ligatures will show >= as ≥
which will just add to the confusion if modifying operators as Vadim
proposes in future scope would ever be added.
Long story short: =|>over |>= IMO has a lot of appeal.
Though, I know not having |>= would deprive us of the "volcano
operator" naming; sorry for being the party pooper.
- Holly brought up this example:
$foo |>= a(…)
$foo |>= b(…)
$foo |>= c(…)
and it seems you talked past each other. Hollys example didn't end lines
with semicolons, while your answer had them. Currently, the
non-semicolon variant:
$foo = "hello";
$foo |>= strtoupper(...) // no semicolon
$foo |>= strtolower(...);
var_dump($foo);
throws with "Parse error: syntax error, unexpected variable "$foo" in".
In the same way the current
$foo = "hello";
$foo |> strtoupper(...) // no semicolon
$foo |> strtolower(...);
var_dump($foo);
throws. I just wanted to point this out because apparently it caused
confusion in the discussion. Perhaps worth to clarify the RFC (even
though it's also current pipe behaviour).
- I recently discovered a bug [1] when pipes are combined with property
hooks. Unsurprisingly, with your addition it is the same. However, since
this shows that pipes are not behaving everywhere identical it would
probably be good to add some tests to confirm the interaction of
assigned pipes with property hooks, readonly etc. -- and maybe also to
clarify it in the RFC.
Cheers
Nick
Hi
I think the latter would be more intuitive: assign the result of piping
to the variable. I know that|>=follows the establishedfoo=
convention for compound assignments like??=or.=; which is an
argument in its favour. Still, I think=|>better communicates how
this particular operation expands. Especially when considering future
additions like the ones Vadim proposes in future scope.
I believe language consistency is of utmost importance for users to
learn and remember fewer special cases.
One additional soft argument is that text ligatures will show >= as ≥
which will just add to the confusion if modifying operators as Vadim
proposes in future scope would ever be added.
It's also not uncommon for them to show |> as ▷, because |> is
established as a pipe operator.
Long story short:
=|>over|>=IMO has a lot of appeal.
I disagree. It looks more like a special form of => rather than an
assignment, which loops back to the “consistency” argument above.
Best regards
Tim Düsterhus
Hey,
Am 20.07.2026 um 14:34 schrieb Tim Düsterhus tim@bastelstu.be:
Hi
I think the latter would be more intuitive: assign the result of piping to the variable. I know that
|>=follows the establishedfoo=convention for compound assignments like??=or.=; which is an argument in its favour. Still, I think=|>better communicates how this particular operation expands. Especially when considering future additions like the ones Vadim proposes in future scope.I believe language consistency is of utmost importance for users to learn and remember fewer special cases.
One additional soft argument is that text ligatures will show >= as ≥ which will just add to the confusion if modifying operators as Vadim proposes in future scope would ever be added.
It's also not uncommon for them to show |> as ▷, because |> is established as a pipe operator.
Long story short:
=|>over|>=IMO has a lot of appeal.I disagree. It looks more like a special form of
=>rather than an assignment, which loops back to the “consistency” argument above.Best regards
Tim Düsterhus
I wholeheartedly agree with Tims assessment here. Also, it's "pipe then assign" - "|>, followed by =".
I absolutely don't like the pipe operator, but pipe-assign (plus some pipes afterward possibly) makes a lot of sense. "Transform this variable", without any repetition.
I'm in favour of this proposal as a whole too.
I just have one more question to the RFC author, which I see in the implementation, but the RFC is not explicitly noting:
Is it intentional that fetching is repeated?
It will literally desugar $a->b->c |>= strtolower(...); to $a->b->c |>= strtolower($a->b->c); resulting in double execution of e.g. property get hooks.
Which in my opinion ought not be the proper behaviour. I acknowledge, that the behaviour is slightly different from the generic operator-assign that other unrelated code can be accessed in between, making RW fetch indirects unsafe - this could obviously be solved perfectly with ad-hoc references in cases the container is an indirect after RW fetching. (i.e. $a[0][0] |>= intval(...); could be like $_container = &$a[0]; $_container[0] |>= intval($_container[0]); - for objects containers or non-nested stuff, it's obviously unneeded.)
Which would the be quite close to actual semantics of other assign-ops.
Nice job on the RFC,
Bob
Hi
I just have one more question to the RFC author, which I see in the
implementation, but the RFC is not explicitly noting:
Is it intentional that fetching is repeated?
I would consider that a bug in the implementation, given that the
“Single-Evaluation Guarantee” section mentions:
When the LHS contains sub-expressions, they are evaluated exactly once:
and
This is the same guarantee that ??= provides over $x = $x ?? default,
implemented using the same compile-time memoization mechanism.
Thus if it behaves differently to ??=, it's a bug in the
implementation :-)
Best regards
Tim Düsterhus
I just have one more question to the RFC author, which I see in the
implementation, but the RFC is not explicitly noting:
Is it intentional that fetching is repeated?
It will literally desugar $a->b->c |>= strtolower(...); to
$a->b->c = strtolower($a->b->c); resulting in double execution
of e.g. property get hooks.
I would consider that a bug in the implementation, given that the
"Single-Evaluation Guarantee" section mentions:When the LHS contains sub-expressions, they are evaluated exactly once:Thus if it behaves differently to
??=, it's a bug in the
implementation :-)
Hi Bob, Tim,
Thanks for flagging this. I tested the scenario Bob described and
|>= behaves identically to ??= here:
class Inner {
public string $c = "hello" {
get { echo "Inner::c GET\n"; return $this->c; }
set(string $v) { echo "Inner::c SET\n"; $this->c = $v; }
}
}
class Outer {
public Inner $b {
get { echo "Outer::b GET\n"; return $this->b; }
}
public function __construct() { $this->b = new Inner(); }
}
$a = new Outer();
$a->b->c |>= strtoupper(...);
// Outer::b GET (read)
// Inner::c GET (read)
// Outer::b GET (write-back)
// Inner::c SET (write-back)
$a->b->c ??= "default";
// Outer::b GET (read)
// Inner::c GET (read)
// Outer::b GET (write-back)
// Inner::c SET (write-back)
Both |>= and ??= fetch the intermediate chain twice (once for the
read, once for the write-back). The single-evaluation guarantee in
the RFC refers to sub-expressions like $arr[expensive_call()],
where the call itself is evaluated only once. That works correctly:
$arr[track()] |>= strtoupper(...);
// track() is called exactly once
So the behavior is consistent with ??=. Bob, your observation about
optimizing intermediate chain fetches with ad-hoc references is
interesting, but that would be an improvement to all compound
assignment operators, not something specific to |>=.
I've updated the RFC to clarify this in the Single-Evaluation
Guarantee section.
- my point is: why
|>=and not=|>?
Hi Nick,
Tim already covered this well, but I agree with him: |>= follows
the established op= convention for compound assignments (+=,
.=, ??=). =|> looks like a special form of => rather than
an assignment, and consistency with existing patterns is worth more
than theoretical future extensibility for operators that may never
materialize.
- Holly's example without semicolons
Yeah, that was just a missing semicolon in the email example;
standard parse error, same as with |>. Nothing to address there.
- I recently discovered a bug [1] when pipes are combined with
property hooks.
Thanks for flagging this. I've added a test (assign_pipe_018.phpt)
that covers |>= with get/set hooks, virtual properties, and
readonly properties. The |>= side works correctly; the bug you
found (#22587) is specific to the base |> operator and is not
introduced or affected by this RFC.
Thanks for testing the implementation and for the detailed feedback!
Best,
Caleb
Hi
So the behavior is consistent with
??=. Bob, your observation about
optimizing intermediate chain fetches with ad-hoc references is
interesting, but that would be an improvement to all compound
assignment operators, not something specific to|>=.I've updated the RFC to clarify this in the Single-Evaluation
Guarantee section.
Thank you. The clarification makes sense to me and I don't have further
comments on the RFC.
As indicated in https://news-web.php.net/php.internals/132049, your RFC
could still be included in PHP 8.6. Even with this clarification, which
is a “minor change” you would be just in time. Any further change to the
RFC text will miss the deadline.
If you want to try to get into PHP 8.6, you'll need to open voting on
the 28th of July very shortly after 04:18 UTC until August 11th the same
time + a bit of buffer. You will also need to send an intent to vote
email at least 48 hours before that. The decision is up to you. I just
wanted to provide you with all the necessary information as a first-time
RFC author to make an adequate decision.
Best regards
Tim Düsterhus
Thank you. The clarification makes sense to me and I don't have further
comments on the RFC.As indicated in https://news-web.php.net/php.internals/132049, your RFC
could still be included in PHP 8.6. Even with this clarification, which
is a “minor change” you would be just in time. Any further change to the
RFC text will miss the deadline.If you want to try to get into PHP 8.6, you'll need to open voting on
the 28th of July very shortly after 04:18 UTC until August 11th the same
time + a bit of buffer. You will also need to send an intent to vote
email at least 48 hours before that. The decision is up to you. I just
wanted to provide you with all the necessary information as a first-time
RFC author to make an adequate decision.Best regards
Tim Düsterhus
Hi Tim,
Thank you for all your help, patience, and guidance throughout this
process, especially as a first-time RFC author. And I really appreciate
you going to bat for this RFC in the thread---thanks again.
I do intend to try to get this into 8.6. Here's the schedule I'm planning:
- Intent to vote: within the next day or so
- Open voting: Monday July 28th ~04:30 UTC
- Voting closes: Monday August 11th ~04:30 UTC
If the vote passes, what's the process for getting the PR merged?
Best,
Caleb
Hi Tim,
Thank you for all your help, patience, and guidance throughout this
process, especially as a first-time RFC author. And I really appreciate
you going to bat for this RFC in the thread---thanks again.I do intend to try to get this into 8.6. Here's the schedule I'm planning:
- Intent to vote: within the next day or so
- Open voting: Monday July 28th ~04:30 UTC
- Voting closes: Monday August 11th ~04:30 UTC
If the vote passes, what's the process for getting the PR merged?
Best,
Caleb
Apparently I got my days mixed up---07-28 and 08-11 are Tuesdays
Best,
Caleb
Hi
I do intend to try to get this into 8.6. Here's the schedule I'm planning:
- Intent to vote: within the next day or so
- Open voting: Monday July 28th ~04:30 UTC
- Voting closes: Monday August 11th ~04:30 UTC
Except for the week-day correction that you noticed yourself, that would
be fully in line with policy and would also be meeting the soft freeze
deadline.
If the vote passes, what's the process for getting the PR merged?
If the vote looks favorable, I'll also have a look at the implementation
(so far I only looked at the tests, I also just added another test
review) and if it looks good to me then I'll find a second reviewer for
the implementation. You'll just have to make sure to react on the review
notes in a timely fashion.
That should hopefully result in the technical review being concluded
before the vote ends, so that the PR is immediately ready for merging.
Given that August 11 is also the day where Beta 1 is tagged, I'll ask
the RMs to merge the PR (if vote is accepted and implementation is
ready, of course) before tagging to avoid any timezone scheduling
issues. After that, PRs may only land with RM approval, but given it’s a
localized change and a small PR, I don't expect the approval to be
denied, but I obviously can’t speak for certain.
Best regards
Tim Düsterhus
Hi internals,
I'd like to open discussion on my (first!) RFC for the pipe assignment operator (|>=):
https://wiki.php.net/rfc/pipe_assignment_operatorIt adds a compound assignment form of the pipe operator, so that
$x |>= callable is shorthand for $x = $x |> callable, with
support for chaining. Implementation with tests is at:
https://github.com/php/php-src/pull/22633Looking forward to your feedback.
Thanks!
Caleb
Hi folks,
The discussion started 2026-07-09, last minor change was 2026-07-21 04:21 UTC;
therefore, the 7-day cooldown expires at 2026-07-28 04:21 UTC.
I intend to open voting on the Pipe Assignment Operator RFC on
2026-07-28 at ~04:30 UTC.
Thanks to everyone who provided feedback during discussion.
Best,
Caleb