List Comprehensions in PHP (how to emulate Python)

Python has a sweet syntactic feature where you can take a literal list written out in bracket notation (e.g. [1, 3, 5, 7, 9]) but have inline expressions generate the list's contents. So instead of writing out the 5 consecutive odd numbers like above, in Python we can say [(x*2+1 for x in range(5)] which turns out to be more characters but you can imagine the savings if the series in the list was longer and not just odd. Instead of range() we could have a literal list [0, 1, 2, 3, 4] or even a generator function, anything which is iterable.

How could we do this in PHP (even newer versions)? There was discussion about adding list comprehensions (or array comprehensions) to PHP around PHP 5.5. Now we're on PHP 7. I don't know what happened.

But if we want to achieve the same thing in order to translate some Python to PHP then we need to be a bit more verbose. Fortunately, for PHP arrays, PHP has included two important higher order functions since old versions of PHP: array_map , array_reduce, and array_filter - or the map/reduce/filter trinity of functional programming.

To emulate the above Python list comprehension in PHP we can write something like this:

<?php $a = array_map(function($x) { return $x*2+1; }, range(0, 5)); ?>

(We can run this in PHP Interactive Shell via php -a)

So the general pattern is to take the list or iterable and imagine it as a PHP array, then take the lambda expression in the prefix of the list comprehension and make it an anonymous function and an argument to array_map(). Let's try another example. First, Python:

squared_evens = lambda max: [x*x for x in range(max) if x % 2 == 0]

Note we are assigning a lambda expression to a variable, squared_evens, so our range function can be arbitrarily and variably large, and that we are applying a condition to the elements of the list: if x % 2 == 0 or only even numbers. Python's list comprehensions combine the map and the filter into a single expression. How can we do this in PHP?

<?php
$squared_evens = function($max) {
  return array_map(function($x) { 
    return $x * $x; 
  }, array_filter(range(0, $max), function($x) { 
    return $x % 2 == 0; 
  }));
};
?>

PHP's array_map and array_filter confusingly and inconsistently take their array argument in opposite order from each other. And although PHP now supports anonymous functions, they seem verbose with the required syntax of the function and return keywords - compared to Python's lambda expressions or ES6's arrow functions. I wrote it out on multiple lines for clarity, otherwise it would be a mess. So while this functional programming construct is possible in PHP, clearly Python is superior at this and we can appreciate Python's native list comprehension syntax.

If you found this interesting you may enjoy List Comprehensions in JavaScript.

Add new comment