DEV Community

david duymelinck
david duymelinck

Posted on

Fixing the array functions for the pipe operator

I had a good conversation with @delacry over the library that was introduced .

And what struck me the most was the last example.

$topAdmins = $users
    |> array_filter(?, fn(User $u) => $u->isActive())
    |> array_map(fn(User $u) => $u->refresh(), ?)
    |> array_filter(?, fn(User $u) => $u->isAdmin())
    |> (fn($us) => (usort($us, fn(User $a, User $b) => $a->name <=> $b->name) ? $us : $us))
    |> array_slice(?, 0, 10);
Enter fullscreen mode Exit fullscreen mode

It is an example with the upcoming partial function application change (PHP 8.6).
I do agree, while it looks miles better than it is in PHP 8.5, it still is not that straight forward as the solutions with the builder pattern.

So I took a bit of time off from my dates project to come up with PAF. POAF looked weird to me, and PAF reminded me of a thing we said in Dutch when I was young, pief poef paf. So that is the whole story behind the name.

The example with the library looks like this.

$topadmins = $users
  |> filterValues(?, fn(User $u) => $u->isActive())
  |> mapSingle(?, fn(User $u) => $u->refresh())
  |> filterValues(?, fn(User $u) => $u->isAdmin(), true)
  |> sortValuesCustom(?, fn(User $a, User $b) => $a->name <=> $b->name)
  |> array_slice(?, 0, 10);
Enter fullscreen mode Exit fullscreen mode

Of course I'm biased, but I don't think anyone is going to say it looks worse.
Functions where the array is the first argument and return an array, like array_slice, don't need to be wrapped.

It is a bit more than a dumb wrapper for the array functions.
Another good point from the conversation was that array_filter leaves gaps in the keys. You could use array_values, but that only solves the problem for the integer keys. For string keys the solution is more complicated.

So I created a reIndex function that takes care of three cases:

  • integers
  • strings
  • custom logic.

In the example you see that is triggered by adding true to the second use of the filterValues function in the chain.
I know using a boolean is controversial, but with named arguments you can do reIndex: true. I'm using them more and more, because they are code as documentation.

I went a bit overboard and I added the function to the map functions. The only use case I can think of at the moment, is using the custom logic to manipulate the keys before going to the next function in the chain.

It is still early days, and I already have a few other directions I want to take for the library. For example the sortValues and sortValuesCustom functions could be one.

It is a small library but I think it has enough value to make it a package. But it has a few more iterations to go before it is ready to be released.

Top comments (0)