# [RFC] Pipe Assignment Operator

- Thread: https://externals.io/message/131849
- Original archive: https://news-web.php.net/php.internals/131849
- Started by Caleb White on 2026-07-10T04:45:32+00:00
- Messages: 38
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/131849.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #131849 — Caleb White — 2026-07-10T04:45:32+00:00

URL: https://externals.io/message/131849#131849

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

---

## #131884 — tim@bastelstu.be — 2026-07-13T14:11:16+00:00

URL: https://externals.io/message/131849#131884 · In reply to: #131849

Hi


> 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

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

---

## #131886 — Caleb White — 2026-07-13T14:24:22+00:00

URL: https://externals.io/message/131849#131886 · In reply to: #131884

> 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

---

## #131887 — tim@bastelstu.be — 2026-07-13T14:33:58+00:00

URL: https://externals.io/message/131849#131887 · In reply to: #131886

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

---

## #131888 — Caleb White — 2026-07-13T14:37:45+00:00

URL: https://externals.io/message/131849#131888 · In reply to: #131887

> 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

---

## #131889 — mickmackusa — 2026-07-13T14:45:38+00:00

URL: https://externals.io/message/131849#131889 · In reply to: #131888

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

---

## #131890 — Ben Ramsey — 2026-07-13T15:11:22+00:00

URL: https://externals.io/message/131849#131890 · In reply to: #131889

> 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

---

## #131892 — Holly Schilling — 2026-07-13T15:54:36+00:00

URL: https://externals.io/message/131849#131892 · In reply to: #131884

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

---

## #131895 — tim@bastelstu.be — 2026-07-13T17:23:35+00:00

URL: https://externals.io/message/131849#131895 · In reply to: #131849

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:

1.

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!

2.

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.

3.

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.

4.

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

---

## #131904 — Caleb White — 2026-07-13T19:02:19+00:00

URL: https://externals.io/message/131849#131904 · In reply to: #131895

> 1.
> 
> 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 :).

> 2.
> 
> 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.

> 3.
> 
> 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.

> 4.
> 
> 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

---

## #131910 — tim@bastelstu.be — 2026-07-14T08:22:04+00:00

URL: https://externals.io/message/131849#131910 · In reply to: #131904

Hi


> > […]
> 
> 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

---

## #131916 — Caleb White — 2026-07-14T11:37:26+00:00

URL: https://externals.io/message/131849#131916 · In reply to: #131910

> 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.

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

---

## #131947 — Larry Garfield — 2026-07-15T21:07:50+00:00

URL: https://externals.io/message/131849#131947 · In reply to: #131849

> 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

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

---

## #131950 — Nick Sdot — 2026-07-15T22:24:31+00:00

URL: https://externals.io/message/131849#131950 · In reply to: #131947

> 
> > […]
> 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

---

## #131952 — drealecs@gmail.com — 2026-07-15T23:14:05+00:00

URL: https://externals.io/message/131849#131952 · In reply to: #131950

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

---

## #131984 — Holly Schilling — 2026-07-16T20:24:42+00:00

URL: https://externals.io/message/131849#131984 · In reply to: #131952

> 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

---

## #132002 — Caleb White — 2026-07-17T20:01:52+00:00

URL: https://externals.io/message/131849#132002 · In reply to: #131984

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

---

## #132018 — Vadim Dvorovenko — 2026-07-19T04:20:26+00:00

URL: https://externals.io/message/131849#132018 · In reply to: #131849

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_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

-- 
--
Vadim Dvorovenko

---

## #132019 — Caleb White — 2026-07-19T04:54:56+00:00

URL: https://externals.io/message/131849#132019 · In reply to: #132018

> 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.

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

---

## #132022 — Vadim Dvorovenko — 2026-07-19T05:37:24+00:00

URL: https://externals.io/message/131849#132022 · In reply to: #132002

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.
>
> 
> > […]
> 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

---

## #132023 — Vadim Dvorovenko — 2026-07-19T06:04:57+00:00

URL: https://externals.io/message/131849#132023 · In reply to: #132019

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 пишет:
> 
> > […]
> 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 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 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

---

## #132025 — Nick Sdot — 2026-07-19T08:35:38+00:00

URL: https://externals.io/message/131849#132025 · In reply to: #131849

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_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

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.

1) 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.

2) 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).

3) 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

[1] https://github.com/php/php-src/issues/22587

---

## #132028 — tim@bastelstu.be — 2026-07-19T12:40:46+00:00

URL: https://externals.io/message/131849#132028 · In reply to: #131916

Hi


> 
> > […]
> 
> 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

---

## #132033 — Caleb White — 2026-07-20T01:07:54+00:00

URL: https://externals.io/message/131849#132033 · In reply to: #132028

> 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

---

## #132034 — Larry Garfield — 2026-07-20T02:11:08+00:00

URL: https://externals.io/message/131849#132034 · In reply to: #132022

> 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.

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

---

Next page: https://externals.io/message/131849.md?page=2
