Hi everyone, thanks for the feedback.

On Friday, July 17th, 2026 at 13:08, Larry Garfield <[email protected]> 
wrote:
> 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.



On Friday, July 17th, 2026 at 13:08, Nick Sdot <[email protected]> wrote:
> 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.



On Friday, July 17th, 2026 at 13:07, Alex Pătrănescu <[email protected]> wrote:
> 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.



On Friday, July 17th, 2026 at 09:54, Holly Schilling 
<[email protected]> wrote:
> 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

Reply via email to