When you start looking into functional programming and functional languages, it’s only a matter of time before you come across the map, reduce and filter functions. Using these functions you can reason about performing actions on collections as a whole, rather than concerning yourself about the internal detail of looping over elements. As you get used to using these functions, you start to see a real elegance in the way they describe the processing of data.

Map, Reduce and Filter in PHP

PHP provides versions of these functions for when you are working with arrays. These are array_map, array_reduce and array_filter. I use these a lot in my PHP code, but there is something which bothers me about them. Before I go into this, let’s look at when we would choose to use each one.

array_map

array_map is used to take one array, and create a new array with a one-to-one mapping of each element processed via a transformation function. Take this example:

$names = [];
foreach ($customers as $customer) {
    $names[] = $customer->getName();
}

The array_map version looks like this:

$names = array_map(
    function ($customer) {
        return $customer->getName();
    },
    $customer
);

array_reduce

array_reduce uses a calculation function to reduce the values of all the elements into a single value. For example:

$total = 0;
foreach ($items as $item) {
    $total += $item->getPrice();
}

The array_reduce version looks like this:

$total = array_reduce(
    $items,
    function ($total, $item) {
        return $total + $item->getPrice();
    },
    0
);

array_filter

array_filter uses a predicate function to filter out unwanted items from an array. For example:

$redCars = [];
foreach ($cars as $car)  {
    if ($car->getColour() === RED) {
        $redCars[] = $car;
    }
}

Using array_filter would look like this:

$redCars = array_filter(
    $cars,
    function ($car) {
        return $car->getColour() === RED;
    }
);

The Problem

One of the nice things about using these functions is that they usually result in neat, concise code. Take the above examples in the following languages:

Ruby

names = customers.map(&:name)
total = items.reduce(0) { |total, item| total + item.price }
red_cars = items.select { |car| car.colour == :red }

Note select is the name Ruby uses for filter.

#### Clojure

(def names (map :name customers))
(def total (reduce (fn [total, item] (+ total (:price item)))))
(def red-cars (filter #(= (:colour %) :red)))

Scala

val names = customers.map(customer => customer.name)
val total = items.foldLeft(0)((total, item) => total + item.price)
val redCars = cars.filter(car => car.color == Red)

(reduce is often also called fold).

As you can see, in most other languages uses of map, reduce and filter are neat, single liners. However, in PHP the overly verbose anonymous function syntax makes them pretty ugly and complicated looking. There was a proposed RFC for a short closure syntax for PHP, which would have enabled us to write nice code like this:

$names = array_map($customer ~> $customer.getName(), $customers);
$total = array_reduce($items, ($total, $item) ~> $total + $item.getPrice);
$redCars = array_filter($cars, $car ~> $car->getColour() === RED);

Sadly the RFC was rejected.

A Solution - Transform and Pentothal

After spending quite some getting time frustrated with the PHP syntax, I decided to do something about it. I started creating a library of functions which each returned a closure to be used as a predicate for array_filter or a transformation for array_map (I use array_reduce much less often).

After starting work, I doubted that I was the first person to do this, so I put it out to Twitter. Giuseppe Mazzapica responded saying that he had a library which provides predicate part of what I was doing - he then promptly uploaded his excellent Pentothal library. From that point on, I decided to just focus on the transformation part - I called this library Transform.

Transform

Transform provides functions which create closures to perform many common actions which you might want to use with array_map. Taking our example above you can use the following code:

use TomPHP\Transform as T;

$names = array_map(T\callMethod('getName'), $customers);

More details about Transform on GitHub.

Pentothal

In the same way, Pentothal provides many functions for generating predicate closures to use with array_filter. Again, taking our earlier example:

use Pentothal as P;

$redCars = array_filter($cars, P\methodReturn('getColour', RED));

More details about Pentothal on GitHub.

Both of these libraries provide a lot of options for most common requirements. By using them the need to write a custom closure for array_map or array_filter is pretty rare.

In conclusion: it looks like PHP 7.1 might finally get a decent, short closure syntax added (PHP RFC: Arrow Functions). But in the meantime, I hope you find these libraries useful.