On Thu, Aug 14, 2025, at 2:30 PM, Larry Garfield wrote:

> So far, the best suggestion that's been put forward (though we've not 
> tried implementing it yet) is to disallow a pipe inside a short-closure 
> body, unless the body is surrounded by ().  So this:
>
> fn($x) => $x 
>   |> fn($x) => array_map(strtoupper(...), $x)
>   |> fn($x) => array_filter($x, fn($v) => $v != 'O');
> 
> Today, that would run somewhat by accident, as the outer-most closure 
> would claim everything after it.  With the new approach, it would be 
> interpreted as passing `fn($x) => $x` as the argument to the first pipe 
> segment, which would then be mapped over, which would fail.  You'd 
> instead need to do this:
>
> fn($x) => ($x 
>   |> (fn($x) => array_map(strtoupper(...), $x))
>   |> (fn($x) => array_filter($x, fn($v) => $v != 'O'))
> );
>
> Which is not wonderful, but it's not too bad, either.  That's probably 
> the only case where pipes inside a short-closure body would be useful 
> anyway.  And if PFA 
> (https://wiki.php.net/rfc/partial_function_application_v2) and similar 
> closure improvements pass, it will greatly reduce the need for mixing 
> short closures and pipes together in either precedence, so it won't 
> come up very often.
>
> There are a few other operators that bind lower than pipe (see 
> https://github.com/php/php-src/blob/fd8dfe1bfda62a3bd9dd1ff7c0577da75db02fcf/Zend/zend_language_parser.y#L56-L73),
>  
> which would therefore need wrapping parentheses.  For many of them we 
> do want them to be lower than pipe, so just moving pipe's priority down 
> isn't viable. However, most of those are unlikely to be used inside a 
> pipe segment, so are less likely to come up.  The most likely would be 
> a bail-out exception:
>
> $value = null;
> $value
>     |> fn ($x) => $x ?? throw new Exception('Value may not be null')
>     |> fn ($x) => var_dump($x);
>
> Which would currently be interpreted something like:
>
> $c = function ($x) {
>   $c = function ($x) {
>     return var_dump($x);
>   };
>   return $x ?? throw $c(new Exception('Value may not be null'));
> };
> $c(null);
>
> This would not throw the exception as expected, unless parentheses are 
> added.  It would var_dump() an exception and then try to throw the 
> return of varl_dump(), which would fatal.
>
> RM approval to address this during the 8.5 beta phase has been given, 
> but we still want to have some discussion to make sure we have a good 
> solution.
>
> So, the question:
>
> 1. Does this seem like a good solution, or is there a problem we've not 
> spotted yet?
> 2. Does anyone have a better solution to suggest?
>
> Thanks to Derick, Ilija, and Tim for tracking down this annoying edge case.

Ilija has implemented the above solution, and it has now been merged.  It's not 
ideal, but it seems like the best option at present.  Hopefully, we can land 
both composition and PFA in 8.6, which should make this situation a fairly rare 
occurrence anyway.

Thanks, Ilija!

--Larry Garfield

Reply via email to