Re: [RFC] Pipe Assignment Operator
| From: | Caleb White | Date: | Tue, 21 Jul 2026 04:18:28 +0000 |
| Subject: | Re: [RFC] Pipe Assignment Operator | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-132063@lists.php.net to get a copy of this message | ||
On Monday, July 20th, 2026 at 14:55, Bob Weinand <bobwei9@hotmail.com> wrote:
> 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.
On Monday, July 20th, 2026 at 15:24, Tim Düsterhus <tim@bastelstu.be> wrote:
> 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.
On Sunday, July 19th, 2026 at 08:35, Nick Sdot <php@nicksdot.dev> wrote:
> 1) 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.
> 2) 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.
> 3) 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