Please wait

Anonymous and Arrow Functions

Anonymous functions, also known as closures, are a feature in PHP where functions can be created without a specific name. This can be useful in scenarios where a function is only used once or is used within another function.

In most programming languages, functions are defined with a specific name, like so:

function greet() {
  echo 'Hello, world!';
}

Here, greet is the name of the function. We can call this function later in our code by its name, like greet();.

Writing anonymous functions

But in some cases, we might have a function that we only need to use once or a function that we want to use as a callback. In these cases, it might be more efficient to use an anonymous function. Here's an example:

$greet = function() {
  echo 'Hello, world!';
};

In this example, we didn't give the function a name. Instead, we assigned it to the variable $greet. Pay close attention, we're adding the ; character after the closing curly bracket. You must add this character since the value is treated as an expression.

Now, we can call this function by using the variable like so:

$greet();

This has many uses, but one common use is when you're working with functions that take other functions as parameters. These are often called 'callback functions'. By using anonymous functions, we can write our code in a more flexible and expressive way.

Why use them?

There are a few reasons why you might want to use anonymous functions (or closures) in your PHP code:

  • Inline function definition: Anonymous functions can be defined right where they're used. This can make the code easier to read, especially if the function is relatively simple and used only once.
  • Callback functions: Anonymous functions are often used as callback functions. A callback function is a function that is passed as an argument to another function and is expected to be executed at a later time. For example, functions like array_map(), array_filter(), and usort() in PHP can take anonymous functions as callbacks.

Let's consider a scenario where you want to create a simple array of numbers and then apply a function to each element of the array. We can do this using the array_map() function and an anonymous function as a callback.

Here's an example:

$numbers = [1, 2, 3, 4, 5];
 
$squared = array_map(function($n) {
  return $n * $n;
}, $numbers);
 
print_r($squared);

Here's what's happening in this code:

  1. We first create an array $numbers that contains a sequence of numbers.
  2. We then use the array_map() function to apply a function to each element of the array. The array_map() function takes two arguments: a callback function that defines the operation to be performed on each element and the array itself.
  3. The callback function is defined as an anonymous function right within the array_map() function call. This anonymous function takes an argument $n and returns the square of $n.
  4. The result is a new array $squared where each element is the square of the corresponding element in the original array. The original array is not modified.
  5. Finally, we use print_r() to print out the contents of the $squared array.

So, if you run this script, you should see the following output, which is the square of each number in the original array:

Array
(
  [0] => 1
  [1] => 4
  [2] => 9
  [3] => 16
  [4] => 25
)

This example shows how anonymous functions can be used to define simple, single-use functions right where they're needed. This can help to keep your code concise and easy to read.

Variable scope

Variables inside a function are not normally accessible outside the function, and variables outside a function are not normally accessible inside the function. This is because each function has its own "scope" for variables.

When we talk about the scope of a variable, we're talking about the part of the code where the variable can be accessed.

Let's start with an example where we try to access a variable from outside an anonymous function:

$message = "Hello, world!";
 
$greet = function() {
  echo $message;
};
 
$greet(); // This will not output anything

If you run this code, you'll find that it doesn't output anything. Even though $message is defined in the global scope, it's not accessible inside the function. This is because $message is not in the function's scope.

Now, if we want an anonymous function to have access to an outside variable, we need to use the use keyword to "import" it into the function's scope:

$message = "Hello, world!";
 
$greet = function() use ($message) {
  echo $message;
};
 
$greet(); // This will output: "Hello, world!"

In this example, we're using the use keyword to tell PHP that we want to use the $message variable inside the function. Now, when we call $greet(), it will have access to $message and will output "Hello, world!" as expected.

It's important to remember that when you import a variable into a function with use, it's actually creating a copy of that variable as it exists at the time the function is defined. If you change the outside variable after the function is defined but before it's called, the function won't see that change.

Let's see an example:

$message = "Hello, world!";
 
$greet = function() use ($message) {
  echo $message;
};
 
$message = "Goodbye, world!";
 
$greet(); // This will still output: "Hello, world!"

In this example, even though we change $message to "Goodbye, world!" before calling $greet(), the function still outputs "Hello, world!". This is because it's working with a copy of $message as it existed at the time the function was defined.

use vs global keywords

The use keyword and the global keyword in PHP are both used to allow a function to access variables from the outer scope, but they work in slightly different ways.

The use keyword is used specifically with anonymous functions (also known as closures) in PHP to import variables from the surrounding scope into the function's scope. When a variable is imported with use, the function creates a copy of that variable as it exists at the time the function is defined. This means that if the outer variable changes after the function is defined but before it's called, the function won't see that change.

Here's an example:

$message = "Hello, world!";
 
$greet = function() use ($message) {
    echo $message;
};
 
$message = "Goodbye, world!";
 
$greet(); // This will still output: "Hello, world!"

As for the global Keyword, this keyword is used inside functions to grant them access to global variables (variables defined in the global scope). Unlike with use, when a function accesses a global variable, it's accessing the actual variable, not a copy. So if the global variable changes after the function is defined, the function will see that change.

Here's an example:

$message = "Hello, world!";
 
function greet() {
    global $message;
    echo $message;
}
 
$message = "Goodbye, world!";
 
greet(); // This will output: "Goodbye, world!"

In general, the use keyword provides a safer way to use outer variables inside a function because it avoids side effects that can occur when a function modifies a global variable. However, the global keyword can be useful when you actually want a function to work with the global variable directly. In most cases, you should avoid the global keyword.

Arrow functions

Arrow functions were introduced in PHP 7.4 as a more concise syntax for writing anonymous functions, especially in situations where you only need a simple expression. The basic structure for arrow functions in PHP is depicted as follows:

fn (parameters) => expression;

In this format, an arrow function:

  • Begins with the fn keyword.
  • Can contain a single expression that is automatically returned.

Here's a practical example1:

$double = fn($n) => $n * 2;

This is an arrow function that takes a number $n and returns the double of that number.

Arrow functions are different from regular anonymous functions in a few ways:

  • Syntax: Arrow functions use the fn keyword instead of the function keyword, and they don't require the use of the return keyword. The value of the expression following the => symbol is automatically returned.
  • Lexical Scoping: Unlike anonymous functions, arrow functions automatically capture variables from the surrounding scope. This is similar to how anonymous functions work when you use the use keyword, but with arrow functions, it's done automatically. You don't need to list the variables you want to use — they're all available.

Here's an example of how an arrow function can access an outer variable:

$message = "Hello, world!";
 
$greet = fn() => $message;
 
echo $greet(); // Outputs: "Hello, world!"

In this example, the arrow function $greet automatically has access to the $message variable, even though we didn't list it with a use keyword.

It's important to note that, like with the use keyword, arrow functions capture the value of outer variables as they are at the time the function is defined. If the outer variable changes later, the function won't see that change.

Also, note that arrow functions in PHP can only contain an expression that becomes the return statement. They can't contain statements or include complex logic like anonymous functions can. They are meant to be short, simple functions.

Since arrow functions return values, you can use the return value after calling the function like so:

$double = fn($n) => $n * 2;
 
echo $double(5); // Outputs: 10

In this example, the arrow function $double takes a single argument $n. The expression after the => symbol is $n * 2, which means "multiply $n by 2". This is the expression that is automatically returned by the arrow function.

So when we call $double(5), we're passing 5 as the argument $n, and the function returns 5 * 2, which is 10. This is why echo $double(5); outputs 10.

This is a very simple example, but it shows how you can use arrow functions to create compact, expressive code in PHP. Arrow functions are particularly useful for simple operations that you want to use as callback functions or for computations you might repeat in different parts of your code.

Exercise

Replace Function Expressions with arrow functions in the code below:

function ask($answer, $yes, $no) {
  if ($answer) {
    $yes();
  } else {
    $no();
  }
}
 
ask(
  true,
  function() {
    echo "You agreed.";
  },
  function() {
    echo "You canceled the execution.";
  }
);

Key takeaways

  • Anonymous functions, also known as closures, are functions without a name.
  • They can be assigned to variables or passed as arguments to other functions.
  • They have their own scope. To use variables from an outer scope, you have to import them using the use keyword.
  • When variables are imported using the use keyword, a copy is created. Therefore, changes to the outer variable after the function creation won't affect the copy inside the function.
  • Anonymous functions can contain complex logic, unlike arrow functions.
  • Arrow functions start with the fn keyword, followed by parameters, and an expression after =>, which is automatically returned.
  • Unlike anonymous functions, arrow functions capture variables from the parent scope automatically. No need to use the use keyword.
  • Arrow functions can only contain a single expression. They can't contain statements or complex logic.

Comments

Please read this before commenting