Fred’s post last week was about filtering through arrays of posts and ordering them. He foreach
ed through arrays, and then used PHP’s usort()
function to get a list of alphabetized posts with comments open. That got me thinking a little bit about a topic I very briefly touched on in my summary of the JavaScript ecosystem: functional programming.
Functional programming is one of the most interesting and valuable things I’ve started to understand in the last few years.
I think functional programming is one of the most interesting and valuable things I’ve started to understand in the last few years. It’s not for everyone though, and it’s not always that relevant to working with WordPress. But it actually shines when doing things like processing and sorting arrays in PHP (again, as Fred’s article offered a way of doing) in a more compact and fluent way. So my hope is to explain some more of the theory of this weird “buzzword” while also giving you concrete and practical uses that you may put it to.
A Quick Summary of Programming Paradigms
foreach
is Procedural
Filtering an array with
foreach
is very “procedural.” That is: we’re describing to the PHP interpreter exactly each step it should go through and what each intermediate state should be.
PHP’s foreach
loops are one of the most useful things a programmer learns early on. The language around them—”For each of the items in this list, do the action inside”—is easy to start to get your head around, somewhat easier than even the simpler functional programming concepts we’ll cover today.
To start to get concrete, we’ll copy some code from Fred’s article. He was looking to create a list of posts with comment open
and closed
, and did it this way:
$posts_by_comment_status = array();
foreach( $posts as $post ) {
$posts_by_comment_status[ $post->comment_status ][] = $post;
}
The result was an array with two indexes — open
and closed
with an array of posts under each. This is quite effective as a way to create that outcome.
It’s also a very “procedural” way to do it. That is: we’re describing to the PHP interpreter exactly each step it should go through and what each intermediate state should be. If parallelization (doing this task in parallel with many different processes) were possible in PHP, it wouldn’t happen here because we’ve defined the procedure as being a linear iteration through one array while inserting elements sequentially into another.
This method is also relying on data from outside the foreach
loop, principally the $posts_by_comment_status
array which is created before it and then used inside of the loop. In this way, the foreach
loop’s “action” has knowledge of what’s outside of it. This is common in WordPress programming, but makes the action inside the foreach
“stateful” in that it knows about and impacts the world in which it lives.
array_filter
is Functional
To accomplish the same basic goal — generate a list of posts whose comment_status
is open and another list whose comments are closed — we could instead use a call to PHP’s array_filter
function. I’m going to quickly show the code — ripping the Band-Aid off — and then we’ll slow down and explain it and all the component concepts.
$posts_with_closed_comments = array_filter(
$posts,
function($post) {
return $post->comment_status === 'closed';
}
);
$posts_with_open_comments = array_filter(
$posts,
function($post) {
return $post->comment_status === 'open';
}
);
Now this code only works in PHP 5.3 and above, but I’ve written it in this way because most WordPress code today is fine with that assumption, and the 5.2-compatible way is slightly harder to make sense of your first time. (For those who need it, we’d pass as the second argument the names of functions that are defined separately where the function(){}
is.)
What are we doing in this example? We’re using the ability to filter
an array to make a new array with only the elements we want. How does this filtering happen? Let’s look more closely at array_filter()
.
How array_filter()
Works
In PHP, array_filter
needs two arguments (and can accept three). They are:
- The array of elements you want to filter.
- The function you want to use to do the filtering. This function should return
true
for values the filters should let through, andfalse
for those it’ll remove. - (Optional) A flag to pass only keys, or both keys and values, of the array to the function. The default, which we’re using here, is passing only the values.
So here we’re able to get an array of just the posts with closed comments by passing as the second argument a function that returns back the result of a comparison between the string value 'closed'
and the string value (either 'open'
or 'closed'
) that will be the value of the post’s comment status. Those posts whose comment status is 'closed'
will thus see a true
returned from the filtering function and be kept. Those that don’t will return false
and therefore be discarded. We can then do the opposite to get those with comments open.
Assuming you truly wanted both sets, not only those in one or the other state, the need to do the array_filter
twice is a bit of a win for the procedural method. But usually for me a foreach
is only keeping some small subset, and this is exactly what array_filter
is for.
What’s Functional About This Example?
The core thing that is “functional” about our examples is that we’re passing a function into another function:
array_filter()
.
One of the more common errors people make after encountering “functional” programming as a concept is to this it’s just about having functions. Personally, I spent more than a year of my life believing I was doing cool, cutting-edge “functional programming” because of this misunderstanding. The core thing that is “functional” about our examples is not just that we’re using the keyword function
(all WordPress programming should do that!), but rather that we’re passing a function into another function: we pass our nameless function (which could maybe have a name like returns_true_if_comment_status_is_open()
) into array_filter()
as its second argument.
The other thing to notice is that the function we’re passing in is “stateless”: it has no knowledge of the rest of code, and does not need it. It merely knows it receives a $post
object as input, and needs only that object to determine what to do. In this way the function is said to be “pure” or “mathematical.” (Conversely, “procedural” functions are almost never “stateless”: their procedures only make sense when the world is in a given configuration which isn’t explicitly elaborated and must be built up by the programmer. A modest example is the empty array Fred created at the start of his foreach
.)
filter()
is one of the best gateways into functional programming, because it requires you start to understand that functions can be very small, very short, and very simple. It points to the expressive benefits you can get from this sort of simple compactness when you pass functions into each other. Procedural code, so common in WordPress, is typified by 10-100 line functions. Getting out of that habit with something like filter
is a great way to start.
Transforming Items in Arrays with a Map
The
filter
andmap
operations are the canonical gateways into functional programming, so I have to bring upmap
.
The filter
and map
operations are the canonical gateways into functional programming, so I have to bring up map
. To do so, we can continue to riff on Fred’s idea of getting posts, filtering them out, and then alphabetizing them. But I’m going to cheat a bit to keep it simple: Fred’s result screenshot only shows names — not links, and not other post data which a real-world use probably requires. But for example purposes, this simple need makes it much easier to use array_map()
to accomplish our goal. So we’ll cheat.
We’re going to get an alphabetized list of post titles, without using the very useful usort()
function Fred used. (You may not have noticed, but usort()
itself is “functional”: you pass a stateless function as an argument to another function.) We’ll instead use array_map()
and PHP’s very simple sort()
function to alphabetize by post title.
Using array_map
Here’s a rough edge of PHP: the order of parameters to array_filter
and array_map
are opposite. Where array_filter
expects your array and then your function, array_map
wants your function and then your array.
With that in mind, we can create an array of post titles from an array of post objects with a simple snippet like this:
$list_of_titles = array_map(
function($post) {
return $post->post_title;
},
$posts
);
Again, we’re using a little function to do an operation inside another function. I think of map
as a little worker: you send the function you pass to map
out to your list, and it does the transformation on every element of that list. To get an array where every element was double the old value, your mapping function would be a simple return $number*2;
. So for us, the function takes each $post
element from the array and gets its post_title
property. What results is an array with identical order, but with only the post titles in the places where the entire post objects were in the original array.
sort()
in Short
PHP can alphabetize for you; sort()
does it. sort()
takes an array, and changes that array to be sorted alphabetically.
The one thing worth some attention is another oddness of PHP: sort
changes (“in place”) what you hand it, and returns either true
or false
based on whether or not it’s able to do the sort. This example highlights the issue I forgetfully have regularly:
$fruits = array("lemon", "orange", "banana", "apple");
$sorted_fruits = sort($fruits);
What this produces:
fruits[0] = apple
fruits[1] = banana
fruits[2] = lemon
fruits[3] = orange
sorted_fruits = true
Just noting the gotcha because if you try to go on to use $sorted_fruits
you will be quite frustrated that it’s true
and not your sorted array. Otherwise, sort
‘s simple enough: it sorts strings in an array alphabetically.
Combining Mapping and Sorting
Now that we understand both array_map()
and sort()
, we just need to combine the two to get an alphabetized array of post titles:
$list_of_titles = array_map(
function($post) {
return $post->post_title;
},
$posts
);
sort($list_of_titles);
Now $list_of_titles
will contain all the titles from the array of $posts
, in alphabetical order.
Just to make a point again, the clever among you may have thought (as I did when assembling the example code): Why don’t I just wrap the sort()
around array_map()
and save myself a line? The reason is again, as we touched on in our section on sort()
, that then your $list_of_titles
would just take the value true
— which would be completely useless to you.
Now You Can Filter and Map
Functional programming is a very useful tool for some jobs, and filtering through a list of items is one of the clearest ones.
Functional programming is a fun thing to play with, and a very powerful tool for many types of problems. Contrary to the impression a reader might reasonably get from my writing about it kind-of-a-lot, I don’t think it’s the new hotness that every WordPress developer needs to know; far from it. But I do think it’s very useful tool for some jobs, and filtering through a list of items is one of the clearest ones.
filter
and map
are very useful to know and understand, even if you never go a step deeper into functional programming. I hope, though, that you found the different tactics used here to solve the problems Fred solved last week interesting and informative. Happy hacking!
[…] The example in this article sorts fetched posts alphabetically by post content (not an option with regular custom queries and loops) with sorting methodologies from basic functional programming, including array_map() and usort(). You can learn these functions in the article, and in our introduction to functional PHP for WordPress developers. […]
[…] function, setInterval. This passing-a-function-to-a-function is the most essential idea of functional programming, but dwelling on that topic isn’t our goal. What you need to understand about this line is that […]
[…] function, setInterval. This passing-a-function-to-a-function is the most essential idea of functional programming, but dwelling on that topic isn’t our goal. What you need to understand about this line is […]
[…] really enjoyed David’s article from a few weeks ago on the basics of functional programming as it applies to WordPress’s nested data structures. One […]
[…] really enjoyed David’s article from a few weeks ago on the basics of functional programming as it applies to WordPress’s nested data structures. […]
[…] as a pragmatic and idiosyncratic language, and you still feel that pain. (I cited a few examples in my recent introduction to functional PHP; the executive summary is simply that the “standard library” is not very standardized.) […]
[…] as a pragmatic and idiosyncratic language, and you still feel that pain. (I cited a few examples in my recent introduction to functional PHP, the executive summary is simply that the “standard library” is not very standardized.) […]
[…] Gentle Introduction to Functional PHP for WordPress Developers: Using Filter and Map on Arrays of Po… […]
I think you explained functional programming very well – great job.