The "pipe operator" |>
allows you to chain multiple function calls in a more convenient way.
$result = "Hello World" |> 'htmlentities' |> 'str_split' |> fn($x) => array_map('strtoupper', $x) |> fn($x) => array_filter($x, fn($v) => $v != 'O');
This RFC was already declined, but we're sharing it here as another test RFC, and because it'd be interesting to learn people's opinion about it.
Pipes are common in many languages and aren't an unfamiliar concept. Whilst there are packages, like Laravel's pipelines, that implement a way to achieve this, this syntactic sugar makes it easy to implement lightweight code for performing a simple series of actions on a subject.
You could do this simply enough in userland code
pipe( 'Hello world', htmlentities(...), 'str_split', fn($x) => array_map('strtoupper', $x), fn($x) => array_filter($x, fn($v) => $v != 'O'), );
function pipe(...$pipes) { $result = array_shift($pipes); foreach ($pipes as $pipe) { $result = $pipe($result); } return $result; }
I do not like this syntax at all and have no problem with user-land solutions.
My chief complaint about the syntax is it blocks functions with multiple parameters. This kneecaps the piping capability, and you're forced back into inside-out calls, or stopping a pipe to call a prohibited function, then start a new pipe with that result.
The operator itself |>
is fine, and to me it reads easily as one expression sending a value forward. What i dislike is the representation of the right-side callable: " Hello world " |> 'trim'
or "Hello world" |> [$object, 'method']
... In my opinion, the language already has too much of this workaround syntax.
First-class callable syntax " Hello world " |> trim(...)
is helpful in that regard, but still falls apart when multiple arguments are needed.
Generally YES, but with some minor change that would allow skipping defining function, so instead of:
$result = "Hello World" |> htmlentities(...) |> str_split(...) |> fn($x) => array_map(strtoupper(...), $x) |> fn($x) => array_filter($x, fn($v) => $v != 'O');
I'd rather see something like
$result = "Hello World" |> htmlentities(...) // or htmlentities(?) |> str_split(...) |> array_map(strtoupper(...), ?) |> array_filter(?, fn($v) => $v != 'O');
This looks like a problem that would be better-solved with a first-party object-oriented API for primitive types (a bit like JavaScript). Honestly the syntax looks a bit odd and as per the example, referencing global functions as strings is an anti-pattern IMO (not friendly for IDEs / refactoring!).
For example:
$result = ("Hello World") // string ->htmlentities(...) ->split(...) // array ->map(fn ($x) => strtoupper($x)) ->filter(fn($v) => $v != 'O');
It's nice to have.
I don't see any advantages and the syntax is a mess.
functions as strings? Bro no way
Improves readabillity drastically
Neat with first class callable syntax
It makes chain calls easier
First, it's really mostly syntactic sugar, adding cognitive load for no added Language-level feature. Besides, it's not clear how easy it would be to step over this code with a debugger.
Second, the argument that the equivalent nested function calls is much less readable, is sound but I think a developer should write neither. Both nested functions calls and chained function calls are hard to live-debug and hard to read, and most of the time in my experience are also an unnecessary micro-optimization.
Third, I think this specific operator "|>" isn't easy to type. The "->" member operator was a mistake of the past, we are stuck with it, don't make another one.
Makes code more readable because has the natural direction of reading (if reading left-to-right, of course)
There is a chain of responsibilities patter that does exactly the same, so I don't see any reason to implement this.
Interface Default Methods improves backwards compatibility when changing interfaces, but also add a way to have multi-inheritance in PHP.
This RFC proposes a way to have multi-line short closures — closures that don't need explicit use
statements, but can still have multiple lines and a return statement.