Re: [PHP-DEV] [RFC] Pipe Assignment Operator
Caleb White <[email protected]> Tue, 21 Jul 2026 04:18:28 +0000
| Newsgroups | gmane.comp.php.devel |
|---|---|
| Message-ID | <rgoknlEYQDatFHhOAqRO1XmuWwBAr8MATveWmG2syA8HthXFGJqm-3a78iBGII4O-o2jP_CVdISkiNQAfQ6f8Yp3NoNtx-soRtSCKoyPNhA=@pm.me> |
On Monday, July 20th, 2026 at 14:55, Bob Weinand <[email protected]> wrot= e: > 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 |>=3D strtolower(...); to > $a->b->c =3D strtolower($a->b->c); resulting in double execution > of e.g. property get hooks. On Monday, July 20th, 2026 at 15:24, Tim D=C3=BCsterhus <[email protected]> = 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 `??=3D`, it's a bug in the > implementation :-) Hi Bob, Tim, Thanks for flagging this. I tested the scenario Bob described and `|>=3D` behaves identically to `??=3D` here: class Inner { public string $c =3D "hello" { get { echo "Inner::c GET\n"; return $this->c; } set(string $v) { echo "Inner::c SET\n"; $this->c =3D $v; } } } class Outer { public Inner $b { get { echo "Outer::b GET\n"; return $this->b; } } public function __construct() { $this->b =3D new Inner(); } } $a =3D new Outer(); $a->b->c |>=3D strtoupper(...); // Outer::b GET (read) // Inner::c GET (read) // Outer::b GET (write-back) // Inner::c SET (write-back) $a->b->c ??=3D "default"; // Outer::b GET (read) // Inner::c GET (read) // Outer::b GET (write-back) // Inner::c SET (write-back) Both `|>=3D` and `??=3D` 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()] |>=3D strtoupper(...); // track() is called exactly once So the behavior is consistent with `??=3D`. 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 `|>=3D`. I've updated the RFC to clarify this in the Single-Evaluation Guarantee section. On Sunday, July 19th, 2026 at 08:35, Nick Sdot <[email protected]> wrote: > 1) my point is: why `|>=3D` and not `=3D|>`? Hi Nick, Tim already covered this well, but I agree with him: `|>=3D` follows the established `op=3D` convention for compound assignments (`+=3D`, `.=3D`, `??=3D`). `=3D|>` looks like a special form of `=3D>` 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 `|>=3D` with get/set hooks, virtual properties, and readonly properties. The `|>=3D` 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