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'))));
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.
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.