01 · THE IDEAREAD → TRY → LEARN
What is a closure?
A normal function has a name. An anonymous function has none, so you usually store it in a variable or pass it straight to another function. PHP represents these values as objects of the built-in Closure class, which is why the words "anonymous function" and "closure" are used almost interchangeably.
Closures are most useful wherever a function expects a callable: sorting with a custom comparison, transforming every element of an array, or filtering a list. Instead of declaring a throwaway named function, you write the behavior right where it is needed.
Creating and calling one
You write the function keyword with no name, followed by parameters and a body. When you assign it to a variable, the statement ends with a semicolon like any other assignment. You then call it by putting parentheses after the variable.
$greet = function (string $name): string {
return "Hello, " . $name . "!";
};
echo $greet("PHP") . "\n";
echo $greet("Ada") . "\n";Hello, PHP! Hello, Ada!
The closure works only with its own parameters here. It cannot see variables from the code around it.
Capturing values with use
A function body has its own scope. Variables defined outside are not visible inside, even when the closure is defined in the same file. To bring an outside variable in, list it in a use (...) clause after the parameter list. If you declare a return type, it goes after the use clause.
By default the variable is captured by value, and the value is copied at the moment the closure is created. Changing the original variable later does not affect the closure.
$rate = 2;
$multiply = function (int $n) use ($rate): int {
return $n * $rate;
};
$rate = 10;
echo $multiply(5) . "\n";10
The output is 10, not 50, because the closure remembered $rate as it was when the closure was defined.
A captured variable cannot have the same name as one of the closure's parameters. Superglobals and $this cannot be listed in use either.
Capturing by reference
Put an ampersand before the name, as in use (&$count), and the closure shares the variable with the outer scope. Changes made inside are visible outside, and later outside changes are visible inside.
$count = 0;
$increment = function () use (&$count): void {
$count++;
};
$increment();
$increment();
echo $count . "\n";2
Reference capture is handy for accumulators, but use it sparingly. A closure that quietly modifies outside state is harder to reason about than one that just returns a value.
Closures that return closures
Because a closure remembers its captured values, a function can build and return a customized closure. The captured value stays alive even after the creating function has finished.
function makeAdder(int $amount): Closure {
return function (int $n) use ($amount): int {
return $n + $amount;
};
}
$addFive = makeAdder(5);
echo json_encode(array_map($addFive, [1, 2, 3])) . "\n";[6,7,8]
Notice that the parent scope of a closure is the function where it was declared, not the place where it is later called. This also differs from global variables: use copies or references one specific variable, it does not open up the global scope.
Things to remember
- Without
use, an outside variable is undefined inside the closure, and PHP emits a warning when you read it. - By-value capture takes a snapshot at definition time.
- By-reference capture shares the variable.
- A closure declared inside a class method is automatically bound to
$this. Declaring it asstatic functionprevents that binding.
Exercise contract
Write scaleAll(int $factor, array $numbers): array. Inside it, build a closure that captures $factor with use, and apply the closure to every element of $numbers using array_map. Return the new array of products. An empty input array must return an empty array, and a factor of 0 must turn every element into 0.
For example, scaleAll(3, [1, 2, 3]) returns [3, 6, 9]. Tests compare the returned array, so do not print anything.
Recap
A closure is a nameless function stored as a value. It sees only its own parameters until you import outer variables with use. Plain use ($x) copies the value when the closure is created, while use (&$x) shares the variable. Returning closures from functions lets you produce small, configured behaviors on demand.
Functions
- Create and call an anonymous function
- Capture a value with use