Functional Programming in PHP: Higher-order Functions

Share this article

Functional Programming in PHP: Higher-order Functions

If you examine several frameworks and large-scale applications, you’ll certainly see a higher-order function at some point. Many languages support the idea of higher-order functions, including JavaScript, Java, .NET, Python and even PHP, to name a few.

But what is a higher-order function and why would we want to use one? What advantages does it give us and can we use it to simplify our code? In this article, we’ll talk about higher-order functions in PHP specifically, but will show how they’ve been used in other languages for comparison.

First-class Functions

Before we can get into what a higher-order function is, we must first understand that we have to have a language that can support a feature called first-class functions (aka first-order functions). This means that the language treats functions as first-class citizens. In other words, the language treats functions like it does variables. You can store a function in a variable, pass it to other functions as a variable, return them from functions like variables and even store them in data structures like arrays or object properties like you can with variables. Most modern languages these days have this feature by default. All you really need to know is that a function can be passed around and used much like variables are.

For our purposes, we’ll be focusing mostly on passing functions as arguments and returning functions as results, and briefly touching on the concept of non-local variables and closures. (You can read more about these concepts in sections 1.1, 1.4 and 1.3 of the Wikipedia article that was linked to in the previous paragraph.)

What Are Higher-order Functions?

There are two main characteristics that identify a higher-order function. A higher-order function can implement just one or both of the following ideas: a function that takes one or more functions as an input or returns a function as an output. In PHP there’s a keyword that’s a clear giveaway that a function is higher-order: the keyword callable. While this keyword doesn’t have to be present, the keyword makes it easy to identify them. If you see a function or method that has a callable parameter, it means that it takes a function as input. Another easy sign is if you see a function return a function using its return statement. The return statement might be just the name of the function, or could even be an anonymous/in-line function. Below are some examples of each type.

// Simple user-defined function we'll pass to our higher-order function
function echoHelloWorld() {
  echo "Hello World!";
}

// Higher-order function that takes a function as an input and calls it
function higherOrderFunction(callable $func) {
  $func();
}

// Call our higher-order function and give it our echoHelloWorld() function. 
// Notice we pass just the name as a string and no parenthesis.
// This echos "Hello World!"
higherOrderFunction('echoHelloWorld'); 

Here are some simple examples of higher-order functions that return a function:

// Returns an existing function in PHP called trim(). Notice it's a simple string with no parentheses.
function trimMessage1() {
  return 'trim';
}

// Here's an example using an anonymous inline function
function trimMessage2() {
    return function($text) {
        return trim($text);
    };
}

// Returns the 'trim' function
$trim1 = trimMessage1(); 

// Call it with our string to trim
echo $trim1('  hello world  ');

// Returns the anonymous function that internally calls 'trim'
$trim2 = trimMessage1(); 

// Call it again with our string to trim
echo $trim2('  hello world  ');

As you can imagine, you can take in a function and also use that to generate another function that’s returned. Pretty neat trick, right? But why would you want to do any of this? It sounds like something that would simply make things more complicated.

Why Would You Use or Create a Higher-order Function?

There are several reasons you might want to create higher-order functions in your code. Everything from code flexibility, code reuse, code extension or to imitate a code solution you saw in another program. While the reasons are numerous, we’ll cover a few of them here.

Adding code flexibility

Higher-order functions add a ton of flexibility. Based on the previous examples, you probably can see a few uses for something like this. You can write a single function that takes in a whole suite of different functions and uses them without having to write code to execute them individually.

Maybe the higher-order function itself doesn’t know what type of function it will receive. Who said that the function has to know anything about the function it’s taking in? One minute the input function could be an add() function, and in the next it could be a divide() function. In either case it just works.

Easily expand your code

This functionality also makes it easier to add additional input functions later. Let’s say you have add() and divide(), but down the road you need to add a sum() function. You can write the sum() function and pipe it through the higher-order function without ever having to change it. In a later example, we’ll demonstrate how we can use this functionality to create our own calc() function.

Imitate features of another language

Another reason you might want to use a higher-order function in PHP is to simulate the behavior of something like a decorator in Python. You “wrap” a function inside another function to modify how that function behaves. For instance, you could write a function that times other functions. You write a higher-order function that takes in a function, starts a timer, calls the function, then ends the timer to see how much time has elapsed.

Examples of Existing Higher-order Functions in PHP

It’s really simple to find examples of higher-order functions in PHP. Look at the PHP documentation and find a function/method that takes a callable input parameter and you’ve found one. Below are a few examples of commonly used higher-order functions. You might have even used them without ever knowing they were higher-order functions.

The higher-order dynamic duo: array_map and array_filter

$arrayOfNums = [1,2,3,4,5];

// array_map: example of taking an inline anonymous function
$doubledNums = array_map(function($num) {
  return $num * 2;
}, $arrayOfNums);

var_dump($doubledNums); // Prints out array containing [2, 4, 6, 8, 10];

Let’s see how to use another one, this time with a filter function we’ve defined separately:

$arrayOfNums = [1,2,3,4,5];

// Example of creating a function and giving it to a higher-order function array_filter()
function isEven($num) {
  return ($num % 2) === 0;
}

// array_filter is a higher-order function
$evenNums = array_filter($arrayOfNums, 'isEven');

var_dump($evenNums); // Prints out array containing [2, 4]

array_filter and array_map are two very popular higher-order functions that you’ll find in plenty of code projects. Another one you might use is call_user_func, which takes in a function and a list of arguments and calls on that function. This is essentially a customized higher-order function. Its whole purpose is to call other functions that the user has defined:

function printCustomMessage($message) {
  echo "$message";
}

call_user_func('printCustomMessage', 'Called custom message through the use of call_user_func!');

How to Create Your Own Higher-order Functions

We’ve shown lots of examples of how higher-order functions work in PHP, and we’ve already created a few custom ones to demonstrate their various purposes. But let’s show off the flexibility a bit more with a new function we’ll call calc(). This function will take in two arguments and a function that will operate on those two arguments to give us a result:

function add($a, $b) {
  return $a + $b;
}

function subtract($a, $b) {
  return $a - $b;
}

function multiply($a, $b) {
  return $a * $b;
}

// Higher-order function that passes along $n1 and $n2
function calc($n1, $n2, $math_func) {
  return $math_func($n1, $n2);
}

$addedNums = calc(1, 5, 'add');
$subtractedNums = calc(1, 5, 'subtract');
$multipliedNums = calc(1, 5, 'multiply');

// Prints 6
echo "Added numbers: $addedNums\n";

// Prints -4
echo "Subtracted numbers: $subtractedNums\n";

// Prints 5
echo "Multiplied numbers: $multipliedNums\n";

Notice that our calc() function was written very generically to take in a set of other functions and calls them with parameters $n1 and $n2. In this case, our calculation function doesn’t care what the function it takes in does. It just passes along the parameters to the function and returns the result.

But wait a minute: our boss just asked us to add a function to add two strings together in our existing system. But concatenating strings isn’t your typical math operation. However, with our setup here, we just need to add in the string concatenation and pipe it through calc():

function addTwoStrings($a, $b) {
  return $a . " " . $b;
}

// Prints "Hello World!"
$concatenatedStrings = calc('Hello', 'World!', 'addTwoStrings');

While this example is very contrived, it demonstrates how you might use the concept in bigger projects. Maybe the higher-order function determines how events are handled. Maybe, based on the event triggered, you can route it through a handler function you pass in. The possibilities are endless.

How does this compare to other languages that have higher-order functions? Let’s take a simple example decorator in Python and compare it to JavaScript and then compare it to PHP. This way, if you know Python or JS, you can see how it is equivalent.

A side-by-side comparison with Python and JavaScript

def say_message(func):
    def wrapper():
        print('Print before function is called')
        func()
        print('Print after function is called')
    return wrapper

def say_hello_world():
    print("Hello World!")

# Pass our hello world function to the say_message function. 
# It returns a function that we can then call
# Note: This line could have been replaced with the @say_message (pie syntax) on the say_hello_world method
say_hello_world = say_message(say_hello_world)

# Call the created function
say_hello_world()

# Output...
# Print before function is called
# Hello World!
# Print after function is called

Now let’s see how this might be achieved in JavaScript higher-order functions:

// Takes a function, returns a function.
function say_message(func) {
  return function() {
      console.log("Print before function is called");
      func();
      console.log("Print after function is called");
  }
}

function say_hello_world() {
  console.log("Hello World!");
}

// Again pass our function to say_message as an input parameter
// say_message returns a function that is wrapped around the say_hello_world function
say_hello = say_message(say_hello_world);

// Call the function
say_hello();

// Output...
// Print before function is called
// Hello World!
// Print after function is called

Now lastly, let’s compare this with PHP:

// Takes a function, returns a function.
function say_message($func) {
  // We use 'use' so that our anonymous function can see $func coming in
  return function() use ($func) {
      echo "Print before function is called";
      $func();
      echo "Print after function is called";
  };
}

function say_hello_world() {
  echo "Hello World!";
}

// Again pass our function to say_message as an input parameter
// say_message returns a function that is wrapped around the say_hello_world function
$say_hello = say_message('say_hello_world');

// Call the function
$say_hello();

// Output...
// Print before function is called
// Hello World!
// Print after function is called

As you can see from the side-by-side comparison, the PHP version is very similar to the JavaScript syntax. But if you know a bit about Python and decorators, you can see how decorators might be translated to one of the other two programming languages.

A Quick Word on Lambdas/Anonymous Functions

Many times, when you’re working with higher-order functions, you may see the use of inline anonymous functions (aka lambdas). In some of the examples we’ve seen above, I’ve used this format. In addition to that, I’ve also used the more explicit version of defining the function first and then passing it to our higher-order function. This is so that you get used to seeing both versions. More often than not, you’ll see the inline lambda version in frameworks that make heavy use of higher-order functions. Don’t let this format throw you. They’re just creating a simple function, without a name, and using that in place of where you’d have given the stand-alone function name.

Conclusion

In this article, we covered the basic definition of what makes a function a higher-order function. Any function that takes in a function or returns a function (or both) can be considered a higher-order function. We also talked a bit about why you might want to create these types of functions and what their advantages are.

We then showed some examples of existing higher-order functions in PHP, like array_map and array_filter, and then went on to create our own higher-order function called calc(), which took several input functions and operated on a couple of arguments. We then went into a side-by-side comparison, showing how PHP’s solution looks compared to a Python decorator and JavaScript implementation. I hope you learned a bit more about higher-order functions and why you might want to consider them in your next large-scale solution. They can offer many advantages and reduce boiler-plate code that may be redundant.

If you’d like to learn more about functional programming in PHP, you can consult our tutorial.

Thanks for reading!

Frequently Asked Questions (FAQs) on Higher-Order Functions in PHP

What is the significance of higher-order functions in PHP?

Higher-order functions in PHP are a fundamental concept in functional programming. They are functions that operate on other functions, either by taking them as arguments or by returning them as results. This allows for more abstract and concise code, leading to improved readability and maintainability. Higher-order functions can help to reduce code duplication and complexity, making your code more efficient and easier to debug.

How do higher-order functions differ from regular functions in PHP?

Regular functions in PHP perform a specific task and return a result. On the other hand, higher-order functions can take one or more functions as arguments, return a function as a result, or both. This allows for greater flexibility and abstraction in your code, enabling you to create more complex functionality with less code.

Can you provide an example of a higher-order function in PHP?

Sure, let’s consider the array_map function in PHP, which is a higher-order function. It takes a callback function and an array as arguments, applies the callback function to each element of the array, and returns a new array with the results.

function square($n) {
return $n * $n;
}

$array = [1, 2, 3, 4, 5];
$result = array_map('square', $array);

print_r($result); // Outputs: Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 16 [4] => 25 )

What are the benefits of using higher-order functions in PHP?

Higher-order functions in PHP provide several benefits. They allow for more abstract and concise code, which can improve readability and maintainability. They can also help to reduce code duplication and complexity, making your code more efficient and easier to debug. Additionally, higher-order functions can facilitate code reuse, as you can pass different functions to a higher-order function to achieve different behaviors.

Are there any drawbacks to using higher-order functions in PHP?

While higher-order functions offer many benefits, they can also have some drawbacks. They can sometimes lead to code that is harder to understand and debug, especially for developers who are not familiar with functional programming concepts. Additionally, the use of higher-order functions can sometimes result in performance overhead, as they often involve creating and invoking additional functions.

How can I create my own higher-order functions in PHP?

Creating your own higher-order functions in PHP involves defining a function that can accept one or more functions as arguments, return a function as a result, or both. Here’s an example of a simple higher-order function that takes a function as an argument and applies it to a value:

function applyFunction($func, $value) {
return $func($value);
}

function square($n) {
return $n * $n;
}

echo applyFunction('square', 5); // Outputs: 25

Can higher-order functions return multiple functions in PHP?

Yes, higher-order functions in PHP can return multiple functions. This is often done by returning an array of functions. However, keep in mind that each returned function will have its own scope and will not share variables with other returned functions.

Can higher-order functions in PHP accept functions from different scopes?

Yes, higher-order functions in PHP can accept functions from different scopes. This is because PHP supports first-class functions, which means that functions can be passed as arguments to other functions, returned by other functions, and assigned to variables.

How do higher-order functions relate to closures in PHP?

Closures in PHP are a type of anonymous function that can capture variables from the surrounding scope. They are often used in conjunction with higher-order functions, as they allow for the creation of functions that have access to more data than just their arguments. This can be useful for creating more flexible and reusable code.

Are there any built-in higher-order functions in PHP?

Yes, PHP provides several built-in higher-order functions. Some examples include array_map, array_filter, and array_reduce. These functions take a callback function as an argument and apply it to the elements of an array in various ways.

Tim HurdTim Hurd
View Author

Tim is a Canadian programming mentor, author, Senior Full Stack developer and founder of The Coders Lexicon. For the past 23+ years he has been specializing in web integrations, API design and system architecture for enterprises in multiple industries including telecommunications, travel and photonics. He spends his time helping other developers with their solutions and contributing over 14k posts covering not just the web, but desktop development as well. He can be found wandering the web through @MartyrsCry.

functional programminghigher order functions
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week