[HN Gopher] PHP 8.5 adds pipe operator
       ___________________________________________________________________
        
       PHP 8.5 adds pipe operator
        
       Author : lemper
       Score  : 410 points
       Date   : 2025-08-05 04:13 UTC (18 hours ago)
        
 (HTM) web link (thephp.foundation)
 (TXT) w3m dump (thephp.foundation)
        
       | bapak wrote:
       | Meanwhile the JS world has been waiting for 10 years for this
       | proposal, which is still in stage 2
       | https://github.com/tc39/proposal-pipeline-operator/issues/23...
        
         | wouldbecouldbe wrote:
         | It's really not needed, syntax sugar. With dots you do almost
         | the same. Php doesn't have chaining. Adding more and more
         | complexity doesn't make a language better.
        
           | EGreg wrote:
           | It's not really chaining
           | 
           | More like thenables / promises
        
             | wouldbecouldbe wrote:
             | It looks like chaining, but with possibility of adding
             | custom functions?
        
               | bapak wrote:
               | It's chaining without having to vary the return of each
               | function. In JS you cannot call 3.myMethod(), but you
               | could with 3 |> myMethod
        
               | cyco130 wrote:
               | It requires parentheses `(3).myMethod()` but you can by
               | monkey patching the Number prototype. Very bad idea, but
               | you absolutely can.
        
               | EGreg wrote:
               | Not only that
               | 
               | In chaining, methods all have to be part of the same
               | class.
               | 
               | In C++ we had this stuff ages ago, it's called abusing
               | streaming operators LMAO
        
           | bapak wrote:
           | Nothing is really needed, C89 was good enough.
           | 
           | Dots are not the same, nobody wants to use chaining like
           | underscore/lodash allowed because it makes dead code
           | elimination impossible.
        
             | pjmlp wrote:
             | K&R C was good enough for UNIX System V, why bother with
             | C89.
        
               | boobsbr wrote:
               | K&R C was the apex, we've just been going downhill since.
        
               | lioeters wrote:
               | This but unironically.
        
           | troupo wrote:
           | > With dots you do almost the same.
           | 
           | Keyword: _almost_. Pipes don 't require you to have many
           | different methods on every possible type:
           | https://news.ycombinator.com/item?id=44794656
        
           | te_chris wrote:
           | Dots call functions on objects, pipe passes arguments to
           | functions. Totally missing the point.
        
           | Martinussen wrote:
           | When you say chaining, do you mean autoboxing primitives? PHP
           | can definitely do things like `foo()->bar()?->baz()`, but
           | you'd have to wrap an array/string yourself instead of the
           | methods being pulled from a `prototype` to use it there.
        
           | chilmers wrote:
           | I'm tired of hearing the exact same arguments, "not needed",
           | "just syntax sugar", "too much complexity", about every new
           | syntax feature that gets added to JS. Somehow, once they are
           | in the language, nobody's head explodes, and people are soon
           | using them and they become uncontroversial.
           | 
           | If people really this new syntax will make it harder to code
           | in JS, show some evidence. Produce a study on solving
           | representative tasks in a version of the language with and
           | without this feature, showing that it has negative effects on
           | code quality and comprehension.
        
             | robertlagrant wrote:
             | Presumably it's up to the change proposers to produce said
             | study showing the opposite.
        
           | purerandomness wrote:
           | If your team prefers not to use this new optional feature,
           | just enable a PHPStan rule in your CI/CD pipeline that
           | prevents code like this getting merged.
        
           | hajile wrote:
           | Chaining requires creating a class and ensuring everything
           | sticks to the class and returns it properly so the chain
           | doesn't blow up. As you add more options and do more stuff,
           | this becomes increasingly hard to write and maintain.
           | 
           | If I'm using a chained library and need another method, I
           | have to understand the underlying data model (a leaky
           | abstraction) and also must have some hack-ish way of
           | extending the model. As I'm not the maintainer, I'm probably
           | going to cause subtle breakages along the way.
           | 
           | Pipe operators have none of these issues. They are obvious.
           | They don't need to track state past the previous operator
           | (which also makes debugging easier). If they need to be
           | extended, look at your response value and add the appropriate
           | function.
           | 
           | Composition (whether with the pipe operator or not) is vastly
           | superior to chaining.
        
         | lacasito25 wrote:
         | in typescript we can do this
         | 
         | let res res = op1() res = op2(res.op1) res = op3(res.op2)
         | 
         | type inference works great, and it is very easy to debug and
         | refactor. In my opinion even more than piping results.
         | 
         | Javascript has enough features.
        
         | avaq wrote:
         | Not only have we been waiting for 10 years, the most likely
         | candidate to go forward is not at all what we wanted when the
         | proposal was created:
         | 
         | We wanted a pipe operator that would pair well with unary
         | functions (like those created by partial function application,
         | which could get its own syntax), but that got rejected on the
         | premise that it would lead to a programming style that utilizes
         | too many closures[0], and which could divide the ecosystem[1].
         | 
         | Yet somehow PHP was not limited by these hypotheticals, and
         | simply gave people the feature they wanted, in exactly the form
         | it makes most sense in.
         | 
         | [0]: https://github.com/tc39/proposal-pipeline-
         | operator/issues/22... [1]: https://github.com/tc39/proposal-
         | pipeline-operator/issues/23...
        
           | lexicality wrote:
           | Am I correct in my understanding that you're saying that the
           | developers of the most widely used JS engine saying "hey we
           | can't see a way to implement this without tanking
           | performance" is a silly hypothetical that should be ignored?
        
             | avaq wrote:
             | They can't implement function application without tanking
             | performance? I find that hard to believe. Especially
             | considering that function application is already a commonly
             | used (and, dare I say: essential) feature in the language,
             | eg: `Math.sqrt(2)`.
             | 
             | All we're asking for is the ability to rewrite that as `2
             | |> Math.sqrt`.
             | 
             | What they're afraid of, my understanding goes, is that
             | people _hypothetically_ , may start leaning more on
             | closures, which themselves perform worse than classes.
             | 
             | However I'm of the opinion that the engine implementors
             | shouldn't really concern themselves to that extent with how
             | people write their code. People can always write slow code,
             | and that's their own responsibility. So I don't know about
             | "silly", but I don't agree with it.
             | 
             | Unless I misunderstood and somehow doing function
             | application a little different is actually a really hard
             | problem. Who knows.
        
               | nilslindemann wrote:
               | Your simple example (`2 |> Math.sqrt`) looks great, but
               | when the code gets more complex, then the advantage of
               | the pipe syntax is less obvious. For example,
               | foo(1, bar(2, baz(3)), 3)
               | 
               | becomes something like                   1 (2, (3 |> baz)
               | > bar), 3 |> foo
               | 
               | or                   (3 |> baz) |> (2, % |> bar) |> (1,
               | %, 3 |> foo)
               | 
               | That looks like just another way to write a thing in
               | JavaScript, and it is not easier to read. What is the
               | advantage?
        
               | avaq wrote:
               | Uhm, don't do it, then. That's like arguing that the
               | addition of the ternary operator is a bad one because not
               | all if/else blocks look better when translated into it.
               | 
               | The goal is to linearlize unary function application, not
               | to make all code look better.
        
               | sir_eliah wrote:
               | I think the commenter meant that once the new syntax is
               | approved and adopted by the community, you have no choice
               | to not use the syntax. You'll eventually change your
               | project and will be forced to deal with reviewing this
               | code.
        
             | jeroenhd wrote:
             | With JS' async/await system basically running on creating
             | temporary closures, I don't think things will change all
             | that much to be honest.
             | 
             | Furthermore, I don't see why engines should police what is
             | or isn't acceptable performance. Using functional
             | interfaces (map/forEach/etc.) is slower than using for
             | loops in most cases, but that didn't stop them from
             | implementing those interfaces either.
             | 
             | I don't think there's that much of a performance impact
             | when comparing                   const x = fun1(abc);
             | const y = fun2(x);         const z = fun3(y);
             | fun4(z);
             | 
             | and                   abc |> fun1 |> fun2 |> fun3 |> fun4
             | 
             | especially when you end up writing code like
             | fun1(abc).then( (x) => fun2(x)).then( (y) =>
             | fun3(y)).then((z) => fun4(z))
             | 
             | when using existing language features.
        
               | ufo wrote:
               | The problem they were discussion in the linked Github
               | issue are pipelines where the functions receive more than
               | one argument.                   const x = fun1(a, 10)
               | const y = fun2(x, 20)         const z = fun3(y, 30)
               | 
               | In this case the pipeline version would create a bunch of
               | throwaway closures.                   a |> ((a) =>
               | fun1(a, 10))           |> ((x) => fun2(x, 20))
               | |> ((y) => fun3(y, 30))
        
             | hajile wrote:
             | Closures won over OOP in Javascript a long time ago (eg,
             | React switching from classes to functions + closures), but
             | they still keep trying to force garbage like private
             | variables on the community.
             | 
             | Loads of features have been added to JS that have worse
             | performance or theoretically enable worse performance, but
             | that never stopped them before.
             | 
             | Some concrete (not-exhaustive) examples:
             | 
             | * Private variables are generally 30-50% slower than non-
             | private variables (and also break proxies).
             | 
             | * let/const are a few percent slower than var.
             | 
             | * Generators are slower than loops.
             | 
             | * Iterators are often slower due to generating garbage for
             | return values.
             | 
             | * Rest/spread operators hide that you're allocating new
             | arrays and objects.
             | 
             | * Proxies cause insane slowdowns of your code.
             | 
             | * Allowing sub-classing of builtins makes everything slow.
             | 
             | * BigInt as designs is almost always slower than the
             | engine's inferred 31-bit integers.
             | 
             | Meanwhile, Google and Mozilla refuse to implement proper
             | tail calls even though they would INCREASE performance for
             | a lot of code. They killed their SIMD projects (despite
             | having them already implemented) which also reduced
             | performance for the most performance-sensitive
             | applications.
             | 
             | It seems obvious that performance is a non-issue when it's
             | something they want to add and an easy excuse when it's
             | something they don't want to add.
        
               | tracker1 wrote:
               | I wish I could upvote this more than once. I really liked
               | the F# inspired pipe operator proposal and even used it a
               | bit when I used to lean on 6to4/babel more, but it just
               | sat and languished forever it seems. I can't really think
               | of any other language feature I've seen since that I
               | would have wanted more. The new Temporal being one
               | exception.
        
               | hajile wrote:
               | It seems like none of the really good language proposals
               | have much traction. Proper Tail Calls have been in the
               | language for TEN YEARS now, but v8 and Spidermonkey still
               | violate the spec and refuse to implement for no good
               | reason.
               | 
               | Record/tuple was killed off despite being the best
               | proposed answer for eliminating hidden class mutation,
               | providing deep O(1) comparisons, and making
               | webworkers/threads/actors worth using because data
               | transfer wouldn't be a bottleneck.
               | 
               | Pattern matching, do expressions, for/while/if/else
               | expressions, binary AST, and others have languished for
               | years without the spec committee seemingly caring that
               | these would have real, tangible upsides for devs and/or
               | users without adding much complexity to the JIT.
               | 
               | I'm convinced that most of the committee is completely
               | divorced from the people who actually use JS day-to-day.
        
               | jedwards1211 wrote:
               | I think it's mainly because they struggled to get
               | consensus on which syntax to go with for pipelines, since
               | people were divided into three different camps. I wish
               | they would just standardize all three options with a
               | slightly different operator for each one
        
               | int_19h wrote:
               | > * Rest/spread operators hide that you're allocating new
               | arrays and objects.
               | 
               | Only in function calls, surely? If you're using spread
               | inside [] or {} then you already know that it allocates.
        
               | hajile wrote:
               | It used to be said that "Lisp programmers know the value
               | of everything and the cost of nothing."
               | 
               | This applies to MOST devs today in my experience and
               | doubly to JS and Python devs as a whole largely due to a
               | lack of education. I'm fine with devs who never went to
               | college, but it becomes an issue when they never bothered
               | to study on their own either.
               | 
               | I've worked with a lot of JS devs who have absolutely no
               | understand of how the system works. Allocation and
               | garbage collection are pure magic. They also have no
               | understanding of pointers or the difference between the
               | stack and heap. All they know is that it's the magic that
               | makes their code run. For these kinds of devs, spread
               | just makes the object they want and they don't understand
               | that it has a performance impact.
               | 
               | Even among knowledgeable devs, you often get the argument
               | that "it's fast enough" and maybe something about
               | optimizing down the road if we need it. The result is a
               | kind of "slow by a thousand small allocations" where your
               | whole application drags more than it should and there's
               | no obvious hot spot because the whole thing is one giant,
               | unoptimized ball of code.
               | 
               | At the end of the day, ease of use, developer ignorance,
               | and deadline pressure means performance is almost always
               | the dead-last priority.
        
             | nobleach wrote:
             | I know that was the reasoning for the Records/Tuples
             | proposal being shot down. I haven't dug too deeply into the
             | pipeline operators other than to get a feel for both
             | proposals.
             | 
             | Most of the more interesting proposals tend to languish
             | these days. When you look at everything that's advanced to
             | Stage 3-4, it's like. "ok, I'm certain this has some
             | amazing perf bump for some feature I don't even use... but
             | do I really care?"
        
           | xixixao wrote:
           | I guess partially my fault, but even in the article, you can
           | see how the Hack syntax is much nicer to work with than the
           | functional one.
           | 
           | Another angle is "how much rewriting does a change require",
           | in this case, what if I want to add another argument to the
           | rhs function call. (I obv. don't consider currying and point-
           | free style a good solution)
        
           | WorldMaker wrote:
           | I am wondering if PHP explicitly rejecting Hack-style pipes
           | (especially given the close ties between PHP and Hack, and
           | that PHP _doesn 't_ have partial application, but JS does,
           | sort of, though its UX could be improved) will add leverage
           | to the F#-style proposal over the Hack-style.
           | 
           | It may be useful data that the TC-29 proposal champions can
           | use to fight for the F# style.
        
         | fergie wrote:
         | Good- the [real world examples of pipes in
         | js](https://github.com/tc39/proposal-pipeline-
         | operator?tab=readm...) are deeply underwhelming IMO.
        
         | defraudbah wrote:
         | do not let me start on monads in golang...
         | 
         | both are going somewhere and super popular though
        
         | 77pt77 wrote:
         | Best you'll git will be 3 new build systems and 10 new
         | frameworks
        
         | epolanski wrote:
         | Sadly they went obsessing over pipes with promises which don't
         | fit the natural flow.
         | 
         | Go explain them that promises already have a natural way to
         | chain operations through the "then" method, and don't need to
         | fit the pipe operator to do more than needed.
        
       | sandreas wrote:
       | While I appreciate the effort and like the approach in general,
       | in this use case I really would prefer extensions / extension
       | functions (like in Kotlin[1]) or an IEnumerable / iterator
       | approach (like in C#).                 $arr = [         new
       | Widget(tags: ['a', 'b', 'c']),         new Widget(tags: ['c',
       | 'd', 'e']),         new Widget(tags: ['x', 'y', 'a']),       ];
       | $result = $arr           |> fn($x) => array_column($x, 'tags') //
       | Gets an array of arrays           |> fn($x) => array_merge(...$x)
       | // Flatten into one big array           |> array_unique(...)
       | // Remove duplicates           |> array_values(...)
       | // Reindex the array.       ;
       | 
       | feels much more complex than writing                 $result =
       | $arr->column('tags')->flatten()->unique()->values()
       | 
       | having array extension methods for column, flatten, unique and
       | values.
       | 
       | 1: https://kotlinlang.org/docs/extensions.html#extension-
       | functi...
        
         | troupo wrote:
         | The advantage is that pipes don't care about the type of the
         | return value.
         | 
         | Let's say you add a reduce in the middle of that chain. With
         | extension methods that would be the last one you call in the
         | chain. With pipes you'd just pipe the result into the next
         | function
        
           | sandreas wrote:
           | Yeah, I agree. That's an advantage of pipes - although much
           | harder to read and write than chained methods in my opinion.
           | 
           | The use-case in the article could still be solved easier with
           | extension methods in my opinion :-)
        
             | troupo wrote:
             | Yeah, the examples should also show that you can use
             | arbitrary functions, not just library functions. E.g. your
             | own business logic, validation etc.
        
         | cess11 wrote:
         | PHP has traits, just invent that API, put it in a trait and add
         | it to your data classes.
        
           | stefanfisk wrote:
           | How would that work if a library supplies a function that
           | takes a string and returns an array? I can't make it use my
           | array class.
        
             | cess11 wrote:
             | Could you give a realistic example?
             | 
             | The PHP pipes as described in the articles about it will
             | require a bunch of wrapping anyway so you could just do
             | that. There are several alternatives, from a function or
             | method that just converts from raw array to class, to
             | abstractions involving stuff like __invoke, __call,
             | dispatchers and such.
             | 
             | Also the expectation to not have to put facades on
             | libraries is a bit suspicious, in my experience it is very
             | common. I find it unlikely you actually want to use raw
             | arrays instead of leveraging type guards in your code.
        
               | stefanfisk wrote:
               | If I use Laravel's Str in an app where both myself and a
               | third party library want to add a chainable method, how
               | do I make the API make sense? We can't both subclass Str.
               | The only option I see is Macroable and that's a rabbit
               | hole I'd rather avoid.
        
           | sandreas wrote:
           | Well, while traits might be a workaround for certain use
           | cases, simple arrays with scalar data types could not be
           | extended via traits.
           | 
           | While I know that there are Collection classes in Symfony,
           | Laravel, etc., I'm not a huge fan of wrapping a PHP array
           | with a class to get method chaining, even with generators.
           | $sum = [1, 2, 3]->filter(fn($x) => $x%2!=
           | 0)->concat([5,7])->sum();
           | 
           | cannot be solved with traits. Additionally, I think traits
           | should be used very carefully and they do not have this many
           | use cases that aren't a code smell to me.
        
         | hn8726 wrote:
         | Kotlin also has extensions function `let` (and a couple of
         | variants) which let you chain arbitrary methods:
         | 
         | ``` val arr = ... val result = arr .let { column(it, "tags")
         | .let { merge(it) } .let { unique(it) } .let { values(it) } ```
         | 
         | You add function references for single-argument functions too:
         | 
         | ``` arr.let(::unique) // or (List<>::unique), depends on the
         | function ```
         | 
         | all without adding a special language construct.
        
         | Contortion wrote:
         | Basically what Collections do in Laravel.
        
           | sandreas wrote:
           | Exactly... similar in Symfony.
           | 
           | While converting arrays to collection-object is a suitable
           | option that does work, it would feel much more "native", if
           | there were extension methods for Iterable / Traversable.
        
       | librasteve wrote:
       | raku has had feed operators like this since its inception
       | # pipeline functional style       (1..5)         ==> map { $_ * 2
       | }         ==> grep { $_ > 5 }         ==> say();              #
       | (6 8 10)            # method chain OO style       (1..5)
       | .map( * * 2)         .grep( * > 5)         .say;
       | # (6 8 10)
       | 
       | uses ==> and <== for leftward
       | 
       | true it is syntax sugar, but often the pipe feed is quite useful
       | to make chaining very obvious
       | 
       | https://docs.raku.org/language/operators#infix_==%3E
        
       | gbalduzzi wrote:
       | I like it.
       | 
       | I really believe the thing PHP needs the most is a rework of
       | string / array functions to make them more consistent and chain
       | able. Now they are at least chainable.
       | 
       | I'm not a fan of the ... syntax though, especially when mixed in
       | the same chain with the spread operator
        
         | noduerme wrote:
         | Agree, the ... syntax feels confusing when each fn($x) in the
         | example uses $x as the name of its argument.
         | 
         | My initial instinct would be to write like this:
         | 
         | `$result = $arr                   |> fn($arr) =>
         | array_column($arr, 'tags') // Gets an array of arrays
         | |> fn($cols) => array_merge(...$cols)`
         | 
         | Which makes me wonder how this handles scope. I'd imagine the
         | interior of some chained function can't reference the input
         | $arr, right? Does it allow pass by reference?
        
           | Einenlum wrote:
           | You can write it this way. The parameter name is arbitrary.
           | And no, to my knowledge you can't access the var from the
           | previous scope
        
           | cess11 wrote:
           | You can do                    function ($parameter) use
           | ($data) { ... }
           | 
           | to capture stuff from the local environment.
           | 
           | Edit: And you can pass by reference:                  >
           | $stuff = [1]        = [            1,          ]
           | > $fn = function ($par) use (&$stuff) { $stuff[] = $par; }
           | = Closure($par) {#3980 ...2}             > $fn(2)        =
           | null             > $stuff        = [            1,
           | 2,          ]
           | 
           | Never done it in practice, though, not sure if there are any
           | footguns besides the obvious hazards in remote mutation.
        
         | colecut wrote:
         | PHP string / array functions are consistent.
         | 
         | string functions use (haystack, needle) and array functions use
         | (needle, haystack)
         | 
         | because that's the way the underlying C libraries also worked
        
           | Einenlum wrote:
           | They're not though.
           | 
           | array_filter takes (arr, callback)
           | 
           | https://www.php.net/manual/en/function.array-filter.php
           | 
           | array_map takes (callback, arr)
           | 
           | https://www.php.net/manual/en/function.array-map.php
        
             | exasperaited wrote:
             | This is "english-sentence-order-consistent", as it goes.
             | 
             | Array filter is "filter this array with this function".
             | 
             | Array map is "map this function over this array".
             | 
             | But I agree any replacement function should be consistent
             | with Haskell.
        
               | eurleif wrote:
               | One can construct English sentences in the opposite
               | order. There is no singular "English sentence order".
               | 
               | "Filter for this function in this array"
               | 
               | "Map over this array with this function"
        
               | exasperaited wrote:
               | Right, but these are both more unwieldy.
               | 
               | One filters something with something else, in the real
               | world. Filter water with a mesh etc.
               | 
               | And (in maths, at least) one maps something onto
               | something else. (And less commonly one maps an area onto
               | paper etc.)
               | 
               | Just because you can make your two sentences does not
               | make them natural word order.
        
               | hnlmorg wrote:
               | When you consider that PHP is used by hundreds of
               | thousands of non-native English speakers, I don't really
               | think you can make a legitimate claim that "English
               | sentence order" trumps "consistent argument ordering".
               | 
               | There's enough viral videos online of how even
               | neighbouring European counties order common sentences
               | differently. Even little things like reading the time
               | (half past the previous hour vs half to the next hour)
               | and counting is written differently in different
               | languages.
               | 
               | So modelling the order of parameters based on English
               | vernacular doesn't make a whole lot of sense for
               | programming languages used by programmers of all
               | nationalities.
        
               | exasperaited wrote:
               | > When you consider that PHP is used by hundreds of
               | thousands of non-native English speakers, I don't really
               | think you can make a legitimate claim that "English
               | sentence order" trumps "consistent argument ordering".
               | 
               | Well that's good, because I didn't.
        
               | quietbritishjim wrote:
               | > And (in maths, at least) one maps something onto
               | something else.
               | 
               | Yes, but that's the opposite of what you said earlier.
               | You might map x onto 2*x, for example. Or, if you're
               | talking about a collection, you might map the integers
               | 0..10 on to double their value. Data first, then the way
               | you're manipulating it. I'm a mathematician and this is
               | what makes sense to me.
               | 
               | I would only say "map this function..." if the function
               | itself is being manipulated somehow (mapped onto some
               | other value).
        
               | goykasi wrote:
               | But thats not correct. array_map is variadic. So it
               | should actually be "Map over these arrays with this
               | function."
               | 
               | When you use the correct verbiage, the parameter order
               | makes sense.
        
             | goykasi wrote:
             | array_map is variadic. It is actually (callback, ...arr)
             | 
             | One function works against a single element, whereas the
             | other works against multiple. In that case, the parameter
             | order is more meaningful. You can use array_walk if you
             | want (arr, callback), but that only works against a single
             | array -- similarly to array_filter.
        
           | Y-bar wrote:
           | > because that's the way the underlying C libraries also
           | worked
           | 
           | I feel like this is a weak defence of the internally
           | inconsistent behaviour. As someone who has been programming
           | with PHP for over twenty years now, most of them
           | professionally, I still cannot remember the needle/haystack
           | order in these functions, I thank intellisense for keeping me
           | sane here.
           | 
           | As evident with this pipe operator, or with for example
           | Attributes, PHP does not need to religiously follow the C way
           | of doing things, so why not improve it instead of dismissing
           | it as "it is the way it is because that is the way it was"?
        
             | chuckadams wrote:
             | It's not so much a defense as it is an explanation of the
             | historical origins. Even the creator of the language
             | doesn't defend the inconsistencies and admits that they
             | were a mistake. PHP also takes backward compatibility
             | pretty seriously and doesn't rearrange things for
             | consistency's sake alone.
        
           | account42 wrote:
           | So they are consistent because they are consistently
           | inconsistent??
           | 
           | There isn't a good reason for PHP to have inherited C's
           | issues here.
        
             | goykasi wrote:
             | In the early days of PHP, it relied heavily on wrapping the
             | underlying C libraries and preserving their naming
             | conventions.
             | 
             | https://news-web.php.net/php.internals/70950
        
               | gbalduzzi wrote:
               | And that was fine in the early days, absolutely.
               | 
               | We are not in the early days though, and in many other
               | aspects PHP evolved greatly.
        
               | goykasi wrote:
               | What are the benefits? Code completion, AI agents, etc
               | will handle it for you. No one's life is falling apart
               | because the param ordering is more similar to C than a
               | blog article complaining about it decade ago. Php devs
               | have had up 30 years to learn the difference. Are C devs
               | complaining about this?
               | 
               | If we want to change the param order of str/array
               | functions for php, I think we should start with fixing
               | the C libraries. That seems like a better starting point.
               | The impact will certainly be more beneficial to even more
               | developers than just php.
        
               | gbalduzzi wrote:
               | Because it would be more predictable, easier to memorize,
               | less verbose, easier to use for developers coming from
               | other modern languages and more comfortable to work with.
               | 
               | The fact that they are chaotic since 30 years ago is not
               | a valid reason for keeping them chaotic right now.
               | 
               | Also, I'm not even arguing they should change the
               | existing functions, that would break all existing code
               | for almost no reason.
               | 
               | I think they should "simply" support methods on
               | primitives, and implement the main ones in a chainable
               | way:
               | 
               | "test string"->trim()->upper()->limit(100);
               | 
               | [0,1,2]->filter(fn ($n) => $n % 2 === 0)->map(fn($n) =>
               | $n * 2);
               | 
               | I would love this so much
        
           | gbalduzzi wrote:
           | `strlen`, `strncmp` and `strtolower` but `str_split` and
           | `str_contains`.
           | 
           | How it that consistent?
        
         | account42 wrote:
         | The syntax could be improved by allowing you to omit the (...)
         | part entirely for single argument functions and using currying
         | for functions that need additional arguments. So you would end
         | up with something like:                 $result = $arr
         | |> select_column('tags')         // Gets an array of arrays
         | |> fn($x) => array_merge(...$x)  // Flatten into one big array
         | |> array_unique                  // Remove duplicates
         | |> array_value                   // Reindex the array.
        
       | keyle wrote:
       | C'mon Dart! Follow up please. Go is a lost cause...
        
         | tayo42 wrote:
         | I feel like a kindergartener writing go. I wish another
         | language got popular in the space go is used for.
        
           | jillesvangurp wrote:
           | Kotlin is shaping up slowly. It's kind of there with a native
           | compiler that is getting better with each release and decent
           | multiplatform libraries. It's a bit weak with support for
           | native libraries and posix stuff. But that's a fixable issue;
           | it just needs more people working on that.
           | 
           | For example ktor (one of the server frameworks) can actually
           | work with Kotlin native but it's not that well supported.
           | This is not using Graal or any of the JVM stuff at runtime
           | (which of course is also a viable path but a lot more
           | heavyweight). With Kotlin native, the Kotlin compiler
           | compiles directly to native code and uses multiplatform
           | libraries with native implementations. There is no Java
           | standard library and none of the jvm libraries are used.
           | 
           | The same compiler is also powering IOS native with Compose
           | multiplatform. On IOS libraries are a bit more comprehensive
           | and it's starting to become a proper alternative to things
           | like flutter and react native. It also has pretty decent
           | objectc and swift integration (both ways) that they are
           | currently working on improving.
           | 
           | In any case, it's pretty easy to write a command line thingy
           | in Kotlin. Use Klikt or similar for command line argument
           | parsing.
           | 
           | Jetbrains seems to be neglecting this a bit for some reason.
           | It's a bit of a blind spot in my view. Their wasm support has
           | similar issues. Works great in browsers (and supported with
           | compose as well) but it's not a really obvious choice for
           | serverless stuff or edge computing just yet; mainly because
           | of the library support.
           | 
           | Swift is a bit more obvious but has the issue that Apple
           | seems to think of it as a library for promoting vendor lockin
           | on their OS rather than as a general purpose language. Both
           | have quite a bit of potential to compete with Go for system
           | programming tasks.
        
       | phplovesong wrote:
       | The stdlib is so inconsistent this will be a nightmare.
       | 
       | Optionally with a better language you know what order params as
       | passed (array_map / array_filter), but in PHP its an coin toss.
       | 
       | This feels very bolted on and not suited for the stdlib at all.
       | 
       | PHP devs should instead FIRST focus on full unicode support (no,
       | the mb_real_uppercase wont do), and only then focus on a new
       | namespaced stdlib with better design.
        
         | Einenlum wrote:
         | This.
         | 
         | We definitely need a better stdlib with appropriate data
         | structures
        
           | allan_s wrote:
           | it's a chicken and the egg problem
           | 
           | I think initiative like this drive a need for a more
           | consistent, and even if slow, PHP has been
           | deprecated/reworking its stdlib so I'm hopeful on this.
        
         | foul wrote:
         | >The stdlib is so inconsistent this will be a nightmare.
         | 
         | I think that callables will end with being useless in this
         | context and everyone will pipe closures to put that $x wherever
         | the stdlib imposes.
        
         | goykasi wrote:
         | Is array_map and array_filter the common argument? One works
         | against a single element, whereas the other works against
         | multiple. What would you suggest a better param order? Do you
         | know that array_walk exists?
        
       | lordofgibbons wrote:
       | Why doesn't PHP remove the horrid $ symbol for variables and the
       | -> symbol for calling methods? I think those alone would do a lot
       | more for its perception and adoption than adding the pipe
       | operator.
        
         | phatskat wrote:
         | I actually don't mind them, and I've been out of daily PHP work
         | for a few years now. When I see people denote internal
         | variables with _ or elements with $ in JS, it rubs me the wrong
         | way, but in PHP the $ is kind of nice.
         | 
         | I also prefer the look of ->, it's _cool_
        
           | kijin wrote:
           | Other languages have all sorts of oversized arrows, like ==>
           | and >>>.
           | 
           | -> in PHP and C++ looks clean by comparison.
           | 
           | I'll never forgive them for the brain fart they made of the
           | namespace separator, though.
        
             | LeonM wrote:
             | > I'll never forgive them for the brain fart they made of
             | the namespace separator, though.
             | 
             | You mean the backslash? What's wrong with that?
        
               | account42 wrote:
               | To someone not already familiar with PHP it looks like
               | you are trying to escape something.
        
               | kijin wrote:
               | The backslash is universally reserved as an escape
               | character.
               | 
               | It was decided almost 20 years ago so I'm totally used to
               | it and there's no point arguing about it anymore. But the
               | decision to reuse the backslash as a namespace separator
               | still causes inconvenience from time to time. For
               | example, when you write PSR-4 configuration in
               | composer.json, all the backslashes need to be doubled,
               | including (and especially!) the trailing backslash.
        
             | esskay wrote:
             | What would the alternative for a namespace separator be?
             | The backslashes work well with PSR-4 to give a logical
             | visual of the expected directory structure.
        
               | account42 wrote:
               | Since PHP takes a lot of syntax from C-like languages,
               | the C++ namespace separator :: would be the obvious
               | choice. Not sure if this conflicted with something in PHP
               | though.
        
               | jimktrains2 wrote:
               | https://www.php.net/manual/en/language.oop5.paamayim-
               | nekudot... scope resolution operator
        
         | ahofmann wrote:
         | I honestly don't understand this. The syntax is one of the most
         | boring parts of a programming language. It is solved by the IDE
         | (and now LLMs). I don't care about syntax, I care about what I
         | can build. Since the beginning of time people argue about
         | things like tabs vs. spaces, or the dollar sign and I honestly
         | don't understand why that is. It just doesn't matter.
         | 
         | Just to be clear: consistency does very much matter. The mental
         | load of reading totally different styles of code is awful and a
         | waste of energy.
        
           | Timwi wrote:
           | Readability (and hence, maintainability) is definitely a
           | factor in decisions like this. In the particular case of the
           | pipe operator though, the article does mention something it
           | lets you do that you couldn't do before: in a context where
           | only an expression is allowed (such as match), you can now do
           | things that previously would not have worked because it would
           | have required temporary variables.
        
         | throw_m239339 wrote:
         | > Why doesn't PHP remove the horrid $ symbol for variables and
         | the -> symbol for calling methods? I think those alone would do
         | a lot more for its perception and adoption than adding the pipe
         | operator.
         | 
         | Because it simply can't do that in a retro-compatible way. ->
         | isn't so bad, C/C++ uses that as well. as for $ I guess it came
         | from Perl. The point is already used for string concatenation,
         | where other languages would overload the + operator.
        
         | jeroenhd wrote:
         | Same reason C doesn't introduce classes and C++ doesn't remove
         | pointers: it's a) part of the core language and b) extremely
         | inconsequential for any serious developer.
         | 
         | I actually like the clarity these dollar signs add in a code
         | base. Makes it easier to recognise (dynamic) functions, and
         | makes it harder to accidentally shadow methods.
         | 
         | Other languages will let you do `const Math = {}` and nuke the
         | entire math library, or write stuff like `int fopen = 0;` to
         | make the fopen method call inaccessible in that scope. With
         | PHP, you don't need to restrict your variable name to
         | "something that hopefully won't conflict with an obscure
         | method".
         | 
         | The -> is a leftover from an older programming language that
         | I'd rather have replaced by a ., but not at the cost of
         | breaking existing code (which it surely would).
        
           | asddubs wrote:
           | I do also appreciate that php has an explicit string concat
           | operator rather than overloading +. Though of course it could
           | just use another symbol for that to get rid of -> if we're
           | talking about time travel. As it stands, you can't really do
           | $obj.method(), because method() could be a function returning
           | a string as well, so it's ambiguous
        
           | account42 wrote:
           | > The -> is a leftover from an older programming language
           | that I'd rather have replaced by a ., but not at the cost of
           | breaking existing code (which it surely would).
           | 
           | Isn't it because . was already used for string concatenation
           | in PHP. I mean the -> syntax wasn't invented by PHP but it
           | didn't just inherit it without thought either.
        
             | int_19h wrote:
             | Indeed. And the reason why PHP used . for string
             | concatenation is because Perl did.
        
         | nolok wrote:
         | Because back compat' is a very strong feature of the language,
         | same reason "match" was created instead of replacing switch.
         | 
         | As a result, taking a php 5.2 script and moving it up to 8.5 is
         | super easy, and taking a PHP 4 one is barely harder only longer
         | (since it probably uses the horrors that were register_globals
         | and co).
         | 
         | Ultimately, I prefer this than a fragmented ecosystem
         | impossible to resolve.
        
         | guskel wrote:
         | The $ symbol gave me RSI as a dev just starting out. I will
         | never forgive PHP for that. Such an unergonomic syntax.
        
         | pkkm wrote:
         | PHP has its significant flaws, but superficial syntactic
         | differences aren't among them. In my experience, it takes two
         | weeks to get used to pretty much any syntax.
        
       | JaggerJo wrote:
       | Thanks F#!
        
       | ChocolateGod wrote:
       | Why not just make types psuedo-objects?
       | 
       | $myString.trim().replace("w", "h");
       | 
       | Which has the advantage of also offering a clean alternative to
       | the fragmented stdlib.
        
         | reddalo wrote:
         | I agree. But in PHP it would probably be like this:
         | 
         | $myString->trim()->replace("w", "h");
        
           | troupo wrote:
           | Because pipes don't care about the type your function
           | returns. And you don't need hundreds of methods on each type
           | just in case. You just pipe the result of the previous
           | function to the next one.
           | 
           | And those functions can be business logic, or validation,
           | or... Not just object methods
        
         | williamdclt wrote:
         | > Why not just make types psuedo-objects?
         | 
         | With this sort of "just" I could build Paris out of matchsticks
        
         | account42 wrote:
         | Because duplicating the stdlib is probably not a good idea.
        
       | habibur wrote:
       | I tried to emulate something similar with PHP at one point. But
       | the problem with PHP was parameter order. Especially in functions
       | like array_key_exists() the array element is the 2nd parameter,
       | while pipe operator expects the object to work on be the 1st
       | parameter, the array in these cases.
       | 
       | I believe they have solved this problem by now. Though no idea
       | how.
        
         | kijin wrote:
         | The usual solution is to wrap it with a closure.
         | function($x) { return array_key_exists('needle', $x); }
         | 
         | Or using the arrow function syntax:                   fn($x) =>
         | array_key_exists('needle', $x)
         | 
         | The same trick also helps when you need to use functions with
         | mandatory extra parameters, functions with pass-by-value
         | parameters, etc.
        
           | moebrowne wrote:
           | If the Partial Function Application RFC passes then the
           | closure wont be necessary
           | 
           | https://wiki.php.net/rfc/partial_function_application_v2
        
       | cess11 wrote:
       | "A major limitation of the pipe operator is that all the
       | callables in the chain must accept only one required parameter.
       | 
       | For built-in functions, if the function does not accept any
       | parameters, it cannot be used in a chain. For user-land PHP
       | functions, passing a parameter to a function that does not accept
       | any parameters does not cause an error, and it is silently
       | ignored.
       | 
       | With the pipe operator, the return value of the previous
       | expression or the callable is always passed as the first
       | parameter to the next callable. It is not possible to change the
       | position of the parameter."
       | 
       | https://php.watch/versions/8.5/pipe-operator
       | 
       | In the light of these limitations I would not call the Elixir
       | implementation "slightly fancier".
       | 
       | I'm not so sure I'll be upgrading my local PHP version just for
       | this but it's nice that they are adding it, I'm sure there is a
       | lot of library code that would look much better if rewritten into
       | this style.
        
       | ossusermivami wrote:
       | i wish python had something liek that to be honest
        
         | kh_hk wrote:
         | one can dream but i wouldn't keep high hopes. I feel functional
         | patterns are left as second class citizens in python.
        
       | abrookewood wrote:
       | I love the pipe operator - one of the things I dig about Elixir
       | though many languages have it. It's so much easier to reason
       | about:                 $result = $arr         |> fn($x) =>
       | array_column($x, 'tags')         |> fn($x) => array_merge(...$x)
       | |> array_unique(...)         |> array_values(...)
       | 
       | VS array_values(array_unique(array_merge(...array_column($arr,
       | 'tags'))));
        
         | qwertox wrote:
         | I don't see how this is hard to reason about, assuming this is
         | the resulting code when using variables:                 $tags
         | = ...array_column($arr, 'tags');       $merged_tags =
         | array_merge($tags);       $unique_tags =
         | array_unique($merged_tags);       $tag_values  =
         | array_values($unique_tags);
         | 
         | It also makes it easier to inspect the values after each step.
        
           | r34 wrote:
           | Your version includes 4 variables. Pipes don't create those
           | intermediate variables, so they are more memory efficient.
           | 
           | Readability is mostly matter of habit. One reads easily what
           | he/she is used to read.
        
             | girvo wrote:
             | > so they are more memory efficient
             | 
             | They can be. It depends on the language, interpreter,
             | compiler, and whether you do anything with those
             | intermediate variables and the optimiser can get rid of
             | them.
        
               | r34 wrote:
               | I thought we are talking about PHP8.5:)
        
               | girvo wrote:
               | Ah, I thought we were talking more generally about PL
               | constructs that let you avoid intermediate variables,
               | apologies :)
        
             | qwertox wrote:
             | It's true that pipes are more readable, and for many cases
             | they will be the better option, but the example of nested
             | functions just doesn't hold.
             | 
             | That's like saying someone would use this:
             | $result = $arr |> fn($x) => array_column($x, 'tags') |>
             | fn($x) => array_merge(...$x) |> array_unique(...) |>
             | array_values(...)
             | 
             | which is harder to reason about than the nested functions.
             | array_values( array_unique( array_merge(
             | ...array_column($arr, 'tags') ) ) );
             | 
             | or                  array_values(          array_unique(
             | array_merge(              ...array_column($arr, 'tags')
             | )          )        );
        
               | navalino wrote:
               | It is more readable and better option -- you have to
               | parse it from the innermost function to the outermost
               | just to understand what it's doing. With the pipe, it's
               | more straightforward: you read it step by step -- do
               | this, then that, then the next -- just like how you'd
               | naturally read instructions.
        
               | account42 wrote:
               | The pipe syntax is much more readable than nested
               | function calls when you need additional arguments for
               | intermediate functions. With nested functions it becomes
               | hard to see which functions those arguments belong to
               | even if you try to help it with formatting.
        
               | troupo wrote:
               | Why didn't you format the pipes, too?
               | $result = $arr         |> fn($x) => array_column($x,
               | 'tags')         |> fn($x) => array_merge(...$x)
               | |> array_unique(...)         |> array_values(...)
               | 
               | vs                  array_values(          array_unique(
               | array_merge(              ...array_column($arr, 'tags')
               | )          )        );
               | 
               | With pipes you have linear sequence of data
               | transformations. With nested function calls you have to
               | start with innermost function and proceed all the way top
               | the outermost layer.
        
           | cess11 wrote:
           | Such variable threading tends to be harder to skim through in
           | production code, the intermediates become noise that's harder
           | to filter out than a repeated symbol like |>.
           | 
           | Preferably you should also be sure that the functions are
           | compatible with the data type going in and only rarely have
           | to break it to dump data mid-chain. If you expect that kind
           | of erroring it's likely a builder-chain with -> is a better
           | alternative and do logging in the methods.
        
           | jeroenhd wrote:
           | Correctly naming things is one of the harder challenges in
           | computer programming. Putting effort into naming
           | intermediates that you're going to throw out is a waste.
           | Plus, the more variables you introduce, the more likely
           | you'll accidentally re-use a variable name somewhere down the
           | line.
           | 
           | With PHP allowing variable initialization in one branch but
           | not the other, and continuing execution by default when an
           | undeclared variable is passed, declaring more variables can
           | lead to an annoying class of bugs that would require
           | significant (breaking) changes to the core language to
           | completely eliminate.
        
           | agos wrote:
           | I don't think inspecting this is easier than adding |>
           | IO.inspect() to a pipe chain
        
             | harg wrote:
             | Or putting `|> dbg()` at the end and let it print the value
             | at every step of the chain
        
             | wraptile wrote:
             | modifying code just to attach a breakpoint is kinda silly
             | in this day and age.
        
           | lawn wrote:
           | Introducing a new variable every single line adda a bunch of
           | cognitive load compared to the pipe operator.
           | 
           | It's much easier skim with the pipe operator and it's more
           | robust too (for example reordering is a pain with variables,
           | it's easy to introduce errors).
        
           | kristopolous wrote:
           | It's easier to write, copy paste, compose and comment
        
           | const_cast wrote:
           | The main problem with this approach, as someone who programs
           | in PHP daily, is it pollutes the scope. That makes debugging
           | much, much harder - you lose track of variables, and the
           | current state of the program is complicated. IMO, if a value
           | is a throwaway, like an intermediate, we shouldn't be able to
           | use it. So method chaining or nesting function calls prevents
           | them. Then, when we break after these functions, we can't see
           | fake values. It also prevents someone in the future mutating
           | the throwaway values. Someone could easily insert logic or a
           | call that mutates something in the middle of this and breaks
           | the chain.
           | 
           | One way this is prevented in PHP is just using functions. But
           | then you have functions just for the sake of scope, which
           | isn't really what they're for. That introduces other
           | annoyances.
        
         | someothherguyy wrote:
         | > It's so much easier to reason about
         | 
         | Is it though? I don't think so.
        
           | andrewflnr wrote:
           | It tends to work a little better in Elixir, because you very
           | rarely have to include one-off lambdas in your pipeline. The
           | standard library functions are designed to work with the
           | pipeline operator, where the thing you probably want to
           | thread through is usually the first argument.
        
       | DataDaemon wrote:
       | This will be the year of PHP. People are tired of JS.
        
         | beardyw wrote:
         | I admire your conviction.
        
         | Timwi wrote:
         | I am indeed tired of JS; however, I'm not a fan of PHP either.
         | I like the new pipe syntax as a concept, but when added to an
         | already uncomfortable overall programming environment, it can
         | only provide mild relief.
        
         | rambambram wrote:
         | You mean the fourth decade of PHP.
        
         | oblio wrote:
         | I'm not a fan of it, but JavaScript will outlive me.
        
         | hajile wrote:
         | I'd rather write JS/TS than most of the other popular
         | languages.
        
       | ioma8 wrote:
       | The syntax is ugly as hell.
        
         | frankzander wrote:
         | Amen ... I mean PHP could have been such a good language if the
         | syntax wouldn't be such a show stopper.
        
         | JohnKemeny wrote:
         | Thank you for your insight.
        
       | someothherguyy wrote:
       | composition would be much nicer than this, maybe soon
        
         | moebrowne wrote:
         | Might be sooner than you think. There are already RFCs for
         | Partial Function Application and Function Composition:
         | 
         | https://wiki.php.net/rfc/partial_function_application_v2
         | https://wiki.php.net/rfc/function-composition
        
       | mappu wrote:
       | Every single one of those steps buffers into a temporary variable
       | - this isn't efficient like a bash pipe.
        
         | quietbritishjim wrote:
         | Genuine question from a non-PHP user:
         | 
         | Does PHP support iterator-like objects? Like Python I mean,
         | where mydict.values() produces values on demand, not
         | immediately realised as a list. Or are all steps necessarily
         | guaranteed to be fully realised into a complete list?
        
           | severak_cz wrote:
           | yes, for a long time -
           | https://www.php.net/manual/en/class.iterator.php
        
             | quietbritishjim wrote:
             | Interesting, but I suppose I was particularly interested if
             | that's what's actually happening with the transformations
             | in the example in the article. Are those making use of this
             | protocol? The comment I originally replied to seems to
             | imply they aren't.
        
           | throw_m239339 wrote:
           | PHP does have generators and iterators yes, although I
           | personally rarely use them directly.
        
           | Timwi wrote:
           | The section where the article mentions function composition
           | implies that it doesn't. The article says that compositing
           | the functions before passing them into map would be an
           | optimization. I take that to mean that without the
           | composition, each map fully processes an array passed to it
           | from the previous map, and the first map fully reads the
           | whole file in the example. If it were iterable, the function
           | composition would make no difference compared to a pipeline
           | of multiple maps.
           | 
           | Meanwhile, I'm confused as to why it sometimes says "map" and
           | sometimes "array_map". The latter is what I'm familiar with
           | and I know that it operates on a whole array with no lazy
           | evaluation. If "map" isn't just a shorthand and actually
           | creates a lazy-evaluated iterable, then I'm confused as to
           | why the function composition would make any difference.
        
         | troupo wrote:
         | That's how function calls work in every language. Unless it's
         | streams.
        
       | dev_l1x_be wrote:
       | Rust is next? Jokes aside, pipe operators in programming
       | languages have a interesting side effect of enabling railway
       | oriented programming that I miss the most when not working in F#.
        
         | simonask wrote:
         | The way function/trait resolution works in Rust, it's actually
         | already quite idiomatic to code in this style (just using the
         | dot operator). The standard library Iterator is a great example
         | of this. :-)
         | 
         | I don't think there's any significant push for an even terser
         | syntax at the moment.
        
         | realharo wrote:
         | There is the `tap` crate (https://crates.io/crates/tap) which
         | adds `tap`, `pipe` and their variants to everything.
        
       | pknerd wrote:
       | Am I the only one who found it ugly?
        
       | defraudbah wrote:
       | PHP is that weird beast that no one wants to praise and yet it
       | works tremendously well for those who manage to tame it.
       | 
       | I would likely never touch it as there are too many languages to
       | use and what I know is more than enough to do my job, but I am
       | super excited to see languages like PHP that aren't mainstream in
       | my bubble to keep evolving
        
         | nolok wrote:
         | I'm not tempting you do to it or anything, but I want to say
         | given your point of view, if one day you need a crude+ app and
         | try to do it using laravel, you might be really surprised by
         | what modern php actually is.
         | 
         | There was a point were I thought the language and it ecosystem
         | was going down the drain but then they recovered and modern php
         | is 90% what do you want to do and don't worry about the how,
         | it's easy.
         | 
         | I don't use it much anymore, but every time I do all I see are
         | possibilities.
        
           | defraudbah wrote:
           | what about deployment? I assume I need to scp files like
           | Python or keep everything in a single giant PHP file? is that
           | an option?
        
             | nolok wrote:
             | Deployment these days is essentially git pull && composer
             | update
             | 
             | Of course not if you use vm or serverless or whatever like
             | this, but for a basic here is my crude app, that's what you
             | do.
             | 
             | Or if you want to go old school sure, just scp that
             | directory, it still works like it did 30 years ago.
        
               | defraudbah wrote:
               | awesome, thank you
        
             | claar wrote:
             | Laravel Forge handles auto-deployment on push to master. Or
             | if you want production zero downtime deployments, use
             | Laravel Envoyer.
        
         | cess11 wrote:
         | I'll gladly praise it. It's a very practical language with good
         | tooling and excellent amounts of libraries and scripts
         | available. Performance is decent, development speed for tools,
         | toys and prototypes is extreme.
         | 
         | The standard library has a lot of good stuff for calling API:s,
         | handling JSON, shelling out, string juggling and HTML
         | publishing on a socket. In every typical install you also have
         | common database interfaces. I've done so much problem solving
         | at breathtaking speed in single file PHP scripts and PsySH over
         | the years.
         | 
         | The threading story isn't or wasn't very good so typically I've
         | done logic in PHP and then driven it from something like a
         | Scheme, Picolisp or Elixir when I've needed it.
        
       | BiteCode_dev wrote:
       | It's lovely to see how PHP keeps growing. It's far from what it
       | was when I used to code with it in V3. I really thought it would
       | be lost in its bad design, but the core devs kept at it, and it
       | is, indeed, a pretty decent language now.
        
       | cpursley wrote:
       | Your move, JavaScript.
        
       | mort96 wrote:
       | I'm surprised that the example requires lambdas... What's the
       | purpose of the `|> foo(...)' syntax if the function has to take
       | exactly one operand? Why is it necessary to write this?
       | $arr             |> fn($x) => array_column($x, 'tags')
       | 
       | Why doesn't this work?                   $arr             |>
       | array_column(..., 'tags')
       | 
       | And when that doesn't work, why doesn't this work?
       | $arr             |> array_unique
        
         | tossandthrow wrote:
         | It is to interject the chained value at the right position in
         | the function.
         | 
         | They write that elixir has a slightly fancier version, it is
         | likely around this, they mean (where elixir has first class
         | support for arity > 1 functions)
        
           | mort96 wrote:
           | But the example suggests that it can't interject the chained
           | value at the right position; if that was the case, the
           | example would've been written as `|> array_column('tags',
           | ...)`.
        
             | wink wrote:
             | yeah that sounds weird. defaulting to the first (or only)
             | parameter would have made sense.
        
         | ptx wrote:
         | Apparently "foo(...)" is just the PHP syntax for a function
         | reference, according to the "first-class callable" RFC [1]
         | linked from the article.
         | 
         | So where in Python you would say e.g.                 callbacks
         | = [f, g]
         | 
         | PHP requires the syntax                 $callbacks = [f(...),
         | g(...)];
         | 
         | As for the purpose of the feature as a whole, although it seems
         | like it could be replaced with function composition as
         | mentioned at the end of the article, and the function
         | composition could be implemented with a utility function
         | instead of dedicated syntax, the advantage of adding these
         | operators is apparently [2] performance (fewer function calls)
         | and facilitating static type-checking.
         | 
         | [1] https://wiki.php.net/rfc/first_class_callable_syntax
         | 
         | [2] https://wiki.php.net/rfc/function-
         | composition#why_in_the_eng...
        
           | mort96 wrote:
           | Thanks, that makes sense!
        
         | moebrowne wrote:
         | There is a complementary RFC for partial function application
         | which will allow calling a function with more than one
         | parameter.
         | 
         | https://wiki.php.net/rfc/partial_function_application_v2
         | https://wiki.php.net/rfc/pipe-operator-v3#rejected_features
        
       | zelphirkalt wrote:
       | Hm. Looks like PHP actually got a modern feature there, and it is
       | looking decent, not like the usual new PHP feature, that just
       | looks worse than in other languages, where it has been standard.
       | Consider me surprised, that they seem to have done a good job on
       | this one. And they even dodged the bullet with making the right
       | side callables, which avoids the trap of inventing new types of
       | expressions and then not covering all cases.
        
       | rogue7 wrote:
       | This looks neat. However since I read about Koka's dot selection
       | [0], I keep thinking that this is an even neater syntax:
       | 
       | fun showit( s : string )
       | s.encode(3).count.println
       | 
       | However, this is of course impossible to implement in most
       | languages as the dot is already meaningful for something else.
       | 
       | [0] https://koka-lang.github.io/koka/doc/book.html#sec-dot
        
         | throw-the-towel wrote:
         | I think this is called uniform function call syntax.
        
         | jprafael wrote:
         | That syntax is very clean when it works. I think however the
         | limitation of not being able to pipe arguments into 2nd, 3rd,
         | ..., positions and keyword arguments, or variadic explosion
         | like the syntax showcased in the article makes it less
         | powerful.
         | 
         | Are there other syntax helpers in that language to overcome
         | this?
        
           | account42 wrote:
           | It still makes sense to have a clean syntax for the simple
           | case. You can use currying (with or without first class
           | language support) to handle more complex cases or just fall
           | back to good old function composition or even loops.
        
         | btbytes wrote:
         | It is called Uniform [Function] Call Syntax.
         | 
         | D has had this for decade(s):
         | https://tour.dlang.org/tour/en/gems/uniform-function-call-sy...
         | 
         | Nim too has it: https://nim-by-example.github.io/oop/
        
       | ds_ wrote:
       | One of the many joys of working with Clojure
       | https://clojure.org/guides/threading_macros
        
       | mhh__ wrote:
       | Every language should have this.
       | 
       | Forget about transforming existing code, it makes new code much
       | more reasonable (the urge to come up with OOPslop is much weaker
       | when functions are trivial) -- they're programming _languages_
       | for a reason.
        
       | xorcist wrote:
       | "Essentially the same thing" as a shell pipe, except each
       | function run sequentially in full, keeping output in a variable.
       | So nothing like a shell pipe.
       | 
       | For short constructions '$out = sort(fn($in)' is really easier to
       | read. For longer you can break them up in multiple lines.
       | $_ = fn_a($in)       $_ = fb_b($_)       $out = fn_c($_)
       | 
       | Is it really "cognitive overhead" to have the temporary variable
       | explicit? Being explicit can be a virtue. Readability matters in
       | a programming language. If nothing else I think Python taught us
       | that.
       | 
       | I am skeptical to these types of sugar. Often what you really
       | want is an iterator. The ability to hide that need carries clear
       | risk.
        
       | lihaciudaniel wrote:
       | Wow dead language adds a special letter wowooeoowowoowoo
        
         | dvtkrlbs wrote:
         | PHP is a dead language since when ?
        
         | zweifuss wrote:
         | It's so dead that 79.2% of all websites rely on PHP to some
         | degree.
         | 
         | https://kinsta.com/php-market-share/
        
       | sumeetdas wrote:
       | The first typed programming language where I've seen pipe
       | operator _| >_ in action was in F#. You can write something like:
       | sum 1 2       |> multiply 3
       | 
       | and it works because _| >_ pushes the output of the left
       | expression as the last parameter into the right-hand function.
       | _multiply_ has to be defined as:                 let multiply b c
       | = b \* c
       | 
       | so that _b_ becomes 3, and _c_ receives the result of _sum 1 2_.
       | 
       | RHS can also be a lambda too:                 sum 1 2 |> (fun x
       | -> multiply 3 x)
       | 
       | _| >_ is not a syntactic sugar but is actually defined in the
       | standard library as:                 let (|>) x f = f x
       | 
       | For function composition, F# provides _> >_ (forward composition)
       | and _< <_ (backward composition), defined respectively as:
       | let (>>) f g x = g (f x)       let (<<) f g x = f (g x)
       | 
       | We can use them to build reusable composed functions:
       | let add1 x = x + 1       let multiply2 x = x \* 2       let
       | composed = add1 >> multiply2
       | 
       | F# is a beautiful language. Sad that M$ stopped investing into
       | this language long back and there's not much interest in (typed)
       | functional programming languages in general.
        
         | christophilus wrote:
         | F# is excellent. It's tooling, ecosystem, and compile times are
         | the reason I don't use it. I learned it alongside OCaml, and
         | OCaml's compilation speed spoiled me.
         | 
         | It is indeed a shame that F# never became a first class
         | citizen.
        
           | cosmos64 wrote:
           | Lots of this, especially the tooling and ecosystem, improved
           | considerably in the last couple of years.
           | 
           | OCaml is a great language, as are others in the ML family.
           | Isabelle is the first language that has introduced the |>
           | pipe character, I think.
        
         | dmead wrote:
         | Haskell seems pretty dead as well. Good think php has another
         | option for line noise though.
        
           | gylterud wrote:
           | What makes you believe Haskell is dead or even dying? New
           | versions of GHC are coming out, and in my experience,
           | developing Haskell has never been smoother (that's not to say
           | it is completely smooth).
        
             | epolanski wrote:
             | And yet, while PHPs, Javas, and even nicher/newer languages
             | like Kotlin, Clojure or Scala have plenty of killer
             | software (software that makes it worth learning a language
             | just to use that library/framework) Haskell has none after
             | 30 years. Zero.
             | 
             | Mind you, I know and like Haskell, but its issues are
             | highly tied to the failure of the simple haskell initiative
             | (also the dreadful state of its tooling).
        
               | dmead wrote:
               | yea I agree. haskell was my primary language for several
               | years in the 00s. it's since had almost zero industry
               | uptake. Don't come at me with jane street or the one off
               | startup.
               | 
               | I thought for a while I'd be able to focus on getting
               | jobs that liked haskell. it never happened.
        
               | chriswarbo wrote:
               | I certainly wouldn't _focus_ on getting a Haskell job.
               | Yet they _are_ out there; e.g. my current job is Haskell,
               | and happens to be in the same sector (public transport)
               | as my last job (which was mostly Scala).
               | 
               | Also, I've found Haskell appropriate for some one-off
               | tasks over the years, e.g.
               | 
               | - Extracting a load of cross-referenced data from a huge
               | XML file. I tried a few of our "common"
               | languages/systems, but they all ran out of memory.
               | Haskell let me quickly write something efficient-enough.
               | Not sure if that's ever been used since (if so then it's
               | definitely tech debt).
               | 
               | - Testing a new system matched certain behaviours of the
               | system it was replacing. This was a one-person task, and
               | was thrown away once the old system was replaced; so no
               | tech debt. In fact, this was at a PHP shop :)
        
               | dmead wrote:
               | Yea of course, its not really the focus for me either
               | way. my point was that how great haskell seemed in grad
               | school didn't match up with the real world interest.
               | 
               | I use spark for most tasks like that now. Guido stole
               | enough from haskell that pyspark is actually quite
               | appealing for a lot of these tasks.
        
               | instig007 wrote:
               | > Guido stole enough from haskell that pyspark is
               | actually quite appealing for a lot of these tasks.
               | 
               | He didn't do his homework. Guido or whoever runs things
               | around the python language committee nowadays didn't have
               | enough mental capacity to realize that the `match` must
               | be a variable bindable expression and never a statement
               | to prevent type-diverging case branches. They also refuse
               | to admit that a non-blocking descriptor on sockets has to
               | be a default property of runtime and never assigned a
               | language syntax for, despite even Java folks proving it
               | by example.
        
               | milutinovici wrote:
               | It has PostgREST, which is the heart of supabase
        
               | gylterud wrote:
               | There are lots of great libraries, like repa, servant,
               | megaparsec, gloss, yampa... as well as bindings to lots
               | of standard stuff. I consider parsing to be one of
               | Haskell's killer strengths and I would definitely use it
               | to write a compiler.
               | 
               | There is also some popular user facing software like
               | Pandoc, written in Haskell. And companies using it
               | internally.
        
               | epolanski wrote:
               | The only non irrelevant compiler ever written in Haskell
               | is for another borderline dead project: Elm.
        
               | gylterud wrote:
               | What are you on about?
               | 
               | The Agda compiler, Pugs, Cryptol, Idris, Copilot (not
               | that copilot you are thinking of), GHC, PureScript,
               | Elm...
               | 
               | These might not be mainstream, but are (or were for Pugs,
               | but the others are current) important within their niche.
        
               | myko wrote:
               | I will not stand for this Xmonad slander
        
               | instig007 wrote:
               | > also the dreadful state of its tooling
               | 
               | this is plain and unsubstantiated FUD
               | 
               | > Haskell has none after 30 years
               | 
               | > I know Haskell
               | 
               | I doubt it
        
             | dmead wrote:
             | it's easy to learn and speak latin as well.
        
               | gylterud wrote:
               | Yes, but there is very little modern latin slang. While
               | GHC gives us great new extensions of Haskell quite often.
        
               | 1-more wrote:
               | Latin never paid my mortgage. Helped on the SATs though.
        
             | munificent wrote:
             | Compare the Redmonk rankings in 2020 to 2025:
             | 
             | https://redmonk.com/sogrady/2020/02/28/language-
             | rankings-1-2...
             | 
             | https://redmonk.com/sogrady/2025/06/18/language-
             | rankings-1-2...
             | 
             | I think of languages as falling in roughly 3 popularity
             | buckets:
             | 
             | 1. A dominant conservative choice. These are ones you never
             | have to justify to your CTO, the "no one ever got fired for
             | buying IBM" languages. That's Java, Python, etc.
             | 
             | 2. A well-known but deliberate choice. These are the
             | languages where there is enough ecosystem and knowledge to
             | be able to justify choosing them, but where doing so still
             | feels like a deliberate engineering choice with some trade-
             | offs and risk. Or languages where they are a dominant
             | choice in one domain but less so in others. Ruby, Scala,
             | Swift, Kotlin.
             | 
             | 3. Everything else. These are the ones you'd have to fight
             | to use professionally. They are either new and innovative
             | or old and dying.
             | 
             | In 2020, Haskell was close to Kotlin, Rust, and Dart. They
             | were in the 3rd bucket but their vector pointed towards the
             | second. In 2025, Kotlin and Dart have pulled ahead into the
             | second bucket, but Haskell is moving in the other
             | direction. It's behind Perl, and Perl itself is not exactly
             | doing great.
             | 
             | None of this is to say that Haskell is a bad language.
             | There are many wonderful languages that aren't widely used.
             | Popularity is hard and hinges on many extrinsic factors
             | more than the merits of the language itself. Otherwise
             | JavaScript wouldn't be at the top of the list.
        
               | instig007 wrote:
               | > In 2020, Haskell was close to Kotlin, Rust, and Dart.
               | [...] In 2025, Kotlin and Dart have pulled ahead into the
               | second bucket, but Haskell is moving in the other
               | direction.
               | 
               | > It's behind Perl, and Perl itself is not exactly doing
               | great.
               | 
               | Your comment reminded me of gamers who "play games" by
               | watching "letsplay" videos on youtube.
        
         | rpeden wrote:
         | Is |> actually an operator in F#? I think it's just a regular
         | function in the standard library but maybe I'm remembering
         | incorrectly.
        
           | laurentlb wrote:
           | It's defined in the standard library and can be redefined by
           | anyone.
           | 
           | It's usually called operator because it uses an infix
           | notation.
        
           | int_19h wrote:
           | All operators are functions in F#, e.g. this is valid: (+) 1
           | 2
        
         | tracker1 wrote:
         | It's kind of wild that PHP gets a pipe(line) operator before JS
         | finalizes its' version... of course they've had multiple
         | competing proposals, of which I liked the F# inspired one the
         | most... I've stopped relying on the likes of Babel (too much
         | bloat) or I'd like to be able to use it. I used it for years
         | for async functions and module syntax before they were
         | implemented in node and browsers. Now it's hard to justify.
        
         | Akronymus wrote:
         | There are also ||> and |||> for automatically destructuring
         | tuples and passing each part as a separate value along.
         | 
         | And there are also the reverse pipes (<|, <|| and <|||)
         | 
         | F# is, for me, the single most ergonomic language to work in.
         | But yeah, M$ isn't investing in it, so there are very few
         | oppurtunities to actually work with f# in the industry either.
        
       | elric wrote:
       | Makes for a fun programming paradigm, similar to Java's streams-
       | with-lambdas. Great for readability. Not too fond of the |>
       | operator though, requires 4 different keypresses on my keyboard
       | layout, not terribly ergonomic. But I understand that options
       | were limited and it is sort of clear.
        
       | major505 wrote:
       | So php now can do clojure like programing?
        
       | donatj wrote:
       | I had this argument in the PHP community when the feature was
       | being discussed, but I think the syntax is much more complicated
       | to _read_ , requiring backtracking to understand. It might be
       | easier to write.
       | 
       | Imagine you're just scanning code you're unfamiliar with trying
       | to identify the symbols. Make sense of inputs and outputs, and
       | you come to something as follows.                   $result =
       | $arr             |> fn($x) => array_column($x, 'values')
       | |> fn($x) => array_merge(...$x)             |> fn($x) =>
       | array_reduce($x, fn($carry, $item) => $carry + $item, 0)
       | |> fn($x) => str_repeat('x', $x);
       | 
       | Look at this operation imaging your reading a big section of code
       | you didn't write. This is embedded within hundreds or thousands
       | of lines. Try to just make sense of what "result" is here? Do
       | your eyes immediately shoot to its final line to get the return
       | type?
       | 
       | My initial desire is to know _what $result is_ generally
       | speaking, before I decide if I want to dive into its derivation.
       | 
       | It's a string. To find that out though, you have to skip all the
       | way to the final line to understand what the type of $result is.
       | When you're just making sense of code, it's far more about the
       | destination than the path to get there, and understanding these
       | require you to read them backwards.
       | 
       | Call me old fashioned, I guess, but the self-documentating nature
       | of a couple variables defining what things are or are doing seems
       | important to writing maintainable code and lowering the
       | maintainers' cognitive load.                   $values =
       | array_merge(...array_column($arr, 'values'));         $total  =
       | array_reduce($values, fn($carry, $item) => $carry + $item, 0);
       | $result = str_repeat('x', $x);
        
         | sandbags wrote:
         | I don't disagree with your reasoning but I would have thought
         | this pipe would be in an appropriately named function (at least
         | that's how I'd use it in Elixir) to help understand the result.
        
         | philjohn wrote:
         | This is what a good IDE brings to the table, it'll show that
         | $result is of type string.
         | 
         | The pipe operator (including T_BLING) was one of the few things
         | I enjoyed when writing Hack at Meta.
        
           | xienze wrote:
           | > This is what a good IDE brings to the table, it'll show
           | that $result is of type string.
           | 
           | I think the parent is referring to what the result _means_,
           | rather than its type. Functional programming can, at times,
           | obfuscate meaning a bit compared to good ol' imperative
           | style.
        
             | 8n4vidtmkvmk wrote:
             | If you want meaning, don't call your variable "result"
        
         | troupo wrote:
         | > I think the syntax is much more complicated to read,
         | requiring backtracking to understand.
         | 
         | Same as with `array_merge(...array_column($arr, 'values'));` or
         | similar nested function calls.
         | 
         | > Imagine you're just scanning code you're unfamiliar with
         | trying to identify the symbols. Make sense of inputs and
         | outputs, and you come to something as follows.
         | 
         | We don't have to imagine :) People working in languages
         | supporting pipes look at similar code all day long.
         | 
         | > but the self-documentating nature of a couple variables
         | defining what things are or are doing seems important to
         | writing maintainable code
         | 
         | Pipes do not prevent you from using a couple of variables.
         | 
         | In your example I need to keep track of $values variable, see
         | where it's used, unwrap nested function calls etc.
         | 
         | Or I can just look at the sequential function calls.
         | 
         | What PHP should've done though is just pass the piped value as
         | the first argument of any function. Then it would be much
         | cleaner:                 $result = $arr         |>
         | array_column('values')         |> array_merge()         |>
         | array_reduce(fn($carry, $item) => $carry + $item, 0)         |>
         | fn($x) => str_repeat('x', $x);
         | 
         | I wouldn't be surprised if that's what will eventually happen
        
           | WorldMaker wrote:
           | The article addresses this pretty well.
           | 
           | Quick summary: Hack used $$ (aka T_BLING) as the implicit
           | parameter in a pipeline. That wasn't accepted as much fun as
           | the name T_BLING can be. PHP looked for a solution and
           | started looking for a Partial Function Application syntax
           | they were happy with. That effort mostly deadlocked (though
           | they hope to return to it) except for syntax
           | some_function(...) for an unapplied function (naming a
           | function without calling it).
           | 
           | Seems like an interesting artifact of PHP functions not being
           | first class objects. I wish them luck on trying to clean up
           | their partial application story further.
        
         | layer8 wrote:
         | I completely agree about intermediate variables (and with
         | explicit type annotations in a typed language) to make the code
         | more intelligible.
         | 
         | But maybe also, the pipe syntax would be better as:
         | $arr         |> fn($x) => array_column($x, 'values')         |>
         | fn($x) => array_merge(...$x)         |> fn($x) =>
         | array_reduce($x, fn($carry, $item) => $carry + $item, 0)
         | |> fn($x) => str_repeat('x', $x)         |= $result;
        
         | drakythe wrote:
         | I don't disagree with you. I had trouble reading the examples
         | at first. But what immediately struck me is this syntax is
         | pretty much identical to chaining object methods that return
         | values.                 $result =
         | $obj->query($sqlQuery)->fetchAll()[$key]
         | 
         | so while the syntax is not my favorite, it at least maintains
         | consistency between method chaining and now function chaining
         | (by pipe).
        
           | 8n4vidtmkvmk wrote:
           | Speaking of query builders, we no longer have to guess
           | whether it's mutating the underlying query object or cloning
           | it with each operation. That's another big win for pipe IMO.
        
         | epolanski wrote:
         | You're conflating different concepts: familiarity and
         | simplicity.
         | 
         | I don't find the pipe alternative to be much harder to read,
         | but I'd also favour the first one.
         | 
         | In any case, we shouldn't judge software and it's features on
         | familiarity.
        
         | mcaruso wrote:
         | People use method chaining all the time and don't have any
         | issue with it? It's equivalent to something like:
         | $result = $arr             ->column('values')
         | ->merge()             ->reduce(fn($carry, $item) => $carry +
         | $item, 0)             ->repeat('x');
         | 
         | I think this just comes down to familiarity.
        
         | altairprime wrote:
         | It reads well to me, as someone familiar with Perl map and jq
         | lambda. But I would syntactic sugar it rather more strongly
         | using a new `|=>` operator implying a distributive `|>` into
         | its now-inferred-and-silent => arguments:
         | $result = $arr |> fn($x) |=>             array_column($x,
         | 'values'),             array_merge(...$x),
         | array_reduce($x, fn($carry, $item) => $carry + $item, 0),
         | str_repeat('x', $x);
         | 
         | As teaching the parser to distribute `fn($x) |=> ELEM1, ELEM2`
         | into `fn($x) => ELEM1 |> fn($x) => ELEM2 |> ...` so that the
         | user isn't wasting time repeating it is exactly the sort of
         | thing I love from Perl, and it's more plainly clear what it's
         | doing -- and in what order, without having to unwrap parens --
         | without interfering with any successive |> blocks that might
         | have different needs.
         | 
         | Of course, since I come from Perl, that lends itself well to
         | cleaning up the array rollup in the middle using a reduce pipe,
         | and then replacing all the words with operators to make
         | incomprehensible gibberish but no longer needing to care about
         | $x at all:                   $result = $arr |> $x:
         | ||> 'values'             |+< $i: $x + $i             |>
         | str_repeat('x', $x);
         | 
         | Which rolls up nicely into a one-liner that is completely
         | comprehensible if you know that | is column, + is merge, < is
         | reduce, and have the : represent the syntactic sugar for
         | conserving repetitions of fn($x) into $x using a stable syntax
         | that the reduce can also take advantage of:
         | $result = $arr |> $x: ||> 'values' |+< $i: $x + $i |>
         | str_repeat('x', $x);
         | 
         | Which reads as a nice simple sentence, since I grew up on Perl,
         | that can be interpreted at a glance because it fits within a
         | glance!
         | 
         | So. I wouldn't necessarily implement _everything_ I can see
         | possible here, because Perl proved that the space of people
         | willing to parse symbols rather than words is not the complete
         | programmer space. But I do stand by the helpfulness of the
         | switch-like |= > as defined above =)
        
         | hombre_fatal wrote:
         | The problem with intermediate assignment is that they pollute
         | your scope.
         | 
         | You might have $values and then you transform it into $b,
         | $values2, $foo, $whatever, and your code has to be eternally
         | vigilant that it never accidentally refers to $values or any of
         | the intermediate variables ever again since they only existed
         | in service to produce some downstream result.
         | 
         | Sometimes this is slightly better in languages that let you
         | repeatedly shadow variables, `$values = xform1($values)`, but
         | we can do better.
         | 
         | That it's hard to name intermediate values is only a symptom of
         | the problem where many intermediate values only exist as
         | ephemeral immediate state.
         | 
         | Pipeline style code is a nice general way to keep the top level
         | clean.
        
           | procaryote wrote:
           | Put it in a function and the scope you pollute is only as big
           | as you make it.
        
             | hombre_fatal wrote:
             | Functions also pollute the scope the same way. And you
             | don't want to be forced to extract a function that is never
             | reused just to hide intermediate values; you should only
             | have to extract a function when you want the abstraction.
             | 
             | The pipeline transformation specifically lets you clean
             | this up with functions at the scope of each ephemeral
             | intermediate value.
        
               | skoskie wrote:
               | That's why we have classes and namespaces.
               | 
               | Anyone can write good or bad code. Avoiding new
               | functionality and syntax won't change that.
        
               | ckdot wrote:
               | You definitely want to extract code into functions, even
               | if you don't need to reuse it. Functions names are
               | documentation. And you reduce the mental load from those
               | who read the code.
        
           | donatj wrote:
           | If PHP scoped to blocks, it would be less of an issue, you
           | could just wrap your procedural code in curly braces and call
           | it a day                   {             $foo = 'bar'; //
           | only defined in this block         }
           | 
           | I use this reasonably often in Go, I wish it were a thing in
           | PHP. PHP allows blocks like this but they seem to be noops
           | best I can tell.
        
         | tracker1 wrote:
         | I think it's more a matter of what you're used to. It's simply
         | an operator and syntax that you aren't used to seeing. Like if
         | they added back a character into English that you aren't
         | familiar with and started using it in words that you no longer
         | recognize.
         | 
         | A lot of people could say the same of the rest/spread syntax as
         | well.
        
         | int_19h wrote:
         | It's no different than chained property accesses or method
         | calls, or more generally nested expressions. Which is to say,
         | if you overuse it, you hamper readability, but if you have a
         | named result for every single operation, it is also hard to
         | read because it introduces too much noise.
        
       | penguin_booze wrote:
       | I don't imagine it's widely known (which I completely
       | understand): vimscript has an arrow operator with similar piping
       | effect, a la foo->bar(baz)->qux() . See the doc:
       | https://vimhelp.org/eval.txt.html#method.
        
       | mg wrote:
       | I'm confused about the rationale behind:                   |>
       | fn($x) => array_column($x, 'tags')
       | 
       | Why is that inlined function necessary? Why not just
       | |> array_column(..., 'tags')
       | 
       | ?
       | 
       | I mean, I understand that it is because the way this operator was
       | designed. But why?
        
         | rafark wrote:
         | > |> array_column(..., 'tags')
         | 
         | This syntax is invalid. But it will be possible next year with
         | the proposed partial function application rfc
         | 
         | array_column(?, 'tags')
         | 
         | https://wiki.php.net/rfc/partial_function_application_v2
        
       | LorenDB wrote:
       | Reminds me of D's Uniform Function Call Syntax[0], which allows
       | you to rewrite bar(foo(sort(myArray))) as
       | myArray.sort().foo().bar(). The difference is that D allows extra
       | function arguments, keeping the passed-in value as the first
       | argument. So you could have myArray.sort().writeln("extra text"),
       | for example.
       | 
       | [0]: https://tour.dlang.org/tour/en/gems/uniform-function-call-
       | sy...
        
       | jcmontx wrote:
       | Very nice, great F# feature, hope to see it in many other
       | languages!
        
       | chuck8088 wrote:
       | This article makes a great case WHY the pipe operator is useful,
       | but why didn't they just rewrite those functions to support
       | method chaining? ` $profit = [1, 4, 5] .loadSeveral()
       | .filter(isOnSale()) .map(sellWidget()) .array_sum(); ` this has
       | the side benefit of 'looking normal'
        
         | wsatb wrote:
         | Backwards compatibility. The language has done a pretty amazing
         | job at adding features over the last 10 years without really
         | breaking a lot of old code. I believe PHP still runs about 75%
         | of the internet, so that's pretty huge.
        
           | moebrowne wrote:
           | The Python 2 to 3 upgrade is a example of how important
           | backwards compatibility is
        
         | troupo wrote:
         | Because pipes work on all functions, not just object methods.
         | So your business logic, validations etc. don't have to be
         | methods of the built-in objects.
         | 
         | And there's nothing abnormal about pipes
        
       | Mystery-Machine wrote:
       | PHP:                       $result = $arr                 |>
       | fn($x) => array_column($x, 'tags') // Gets an array of arrays
       | |> fn($x) => array_merge(...$x)       // Flatten into one big
       | array                 |> array_unique(...)                  //
       | Remove duplicates                 |> array_values(...)
       | // Reindex the array.             ; // <- wtf
       | 
       | Ruby:                   result = arr.uniq.flatten.map(&:tags)
       | 
       | I understand this is not pipe operator, but just look at that
       | character difference across these two languages.
       | 
       | // <- wtf
       | 
       | This comment was my $0.02.
        
         | Alifatisk wrote:
         | Can't the pipe operator be easily mimicked in Ruby thanks to
         | its flexibility?
         | 
         | I'm thinking of something like this:                   class
         | Object           def |>(fn)             fn.call(self)
         | end         end
         | 
         | which then can be in the following way:
         | result = arr           |> ->(a) { a.uniq }           |> ->(a) {
         | a.flatten }           |> ->(a) { a.map(&:tags) }
         | 
         | Or if we just created an alias for then #then method:
         | class Object           alias_method :|>, :then         end
         | 
         | then it can be used like in this way:                   arr
         | |> :uniq.to_proc           |> :flatten.to_proc           |>
         | ->(a) { a.map(&:tags) }
        
           | rafark wrote:
           | The great thing about this pipe operator is that it accepts
           | any callable expression. I'm writing a library to make these
           | array and string functions more expressive.
           | 
           | For example, in php 8.5 you'll be able to do:
           | 
           | [1,1,2,3,2] |> unique
           | 
           | And then define "unique" as a constant with a callback
           | assigned to it, roughly like:
           | 
           | const unique = static fn(array $array) : array =>
           | array_unique($array);
           | 
           | Much better.
        
         | moebrowne wrote:
         | The trailing semi-colon on a new line helps prevent Git
         | conflicts and gives cleaner diffs.
         | 
         | It's the same reason PHP allows trailing commas in all lists.
        
         | daneel_w wrote:
         | Putting the delimiter on a line of its own is a syntactical
         | trick that helps bringing small additions down to a neater
         | 1-line diff instead of a 2-line diff. You've probably run into
         | it many times before in other contexts without thinking of it.
         | Arrays/hashes, quoted multi-line strings etc.
        
       | jadbox wrote:
       | Now if only JS or Typescript can jump on this ship!
        
       | scop wrote:
       | This is great! Hat tip to PHP. I first came across pipes in
       | Elixir and have ever since missed it in every other language. Two
       | observations:
       | 
       | - pipes make you realize how much song and dance you do for
       | something quite simple. Nesting, interstitial variables, etc all
       | obscuring what is in effect and very orderly set of operations.
       | 
       | - pipes really do have to be a first class operator of the
       | language. I've tried using some pipe-like syntactic sugar in
       | languages without pipes and while it does the job, a lot of
       | elegance and simplicity is lost. It feels like you are using a
       | roundabout thing and thus, in the end, doesn't really achieve the
       | same level of simplicity. Things can get very deranged if you are
       | using a language in a way it wasn't designed for and even though
       | I love pipes I've seen "fake pipes" make things more complicated
       | in languages without them.
        
       | elif wrote:
       | I used php professionally for a decade and I still don't get why
       | in the year 2025 we need to reinvent syntax that is virtually
       | standard in every language
        
       | dagi3d wrote:
       | I wish they reconsider it again i ruby
        
       | adius wrote:
       | PHP getting a pipe operator with ways to implement a Maybe Monad
       | was definitely not on my 2025 bingo card.
       | 
       | But any changes making mainstream languages more functional are
       | highly welcome! It's just more ergonomic than imperative code.
        
       | flufluflufluffy wrote:
       | It's cool. Personally I probably won't be using it though. I
       | think a few temp variables or dedicated functions to do some
       | computation that takes more than 2 or 3 iterated operations is
       | better for readability and maintainability.
        
       ___________________________________________________________________
       (page generated 2025-08-05 23:01 UTC)