Lesson 15 of 100
Functions12 min5 checksPHP 8.5

Closures and the use Keyword

Learn how anonymous functions work in PHP, how use captures values from the parent scope, and when to capture by value or by reference.

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.

Example
<?php
$greet = function (string $name): string {
    return "Hello, " . $name . "!";
};
echo $greet("PHP") . "\n";
echo $greet("Ada") . "\n";
Output
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.

Example
<?php
$rate = 2;
$multiply = function (int $n) use ($rate): int {
    return $n * $rate;
};
$rate = 10;
echo $multiply(5) . "\n";
Output
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.

Example
<?php
$count = 0;
$increment = function () use (&$count): void {
    $count++;
};
$increment();
$increment();
echo $count . "\n";
Output
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.

Example
<?php
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";
Output
[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 as static function prevents 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.

Before you start

Functions

You’ll practice
  • Create and call an anonymous function
  • Capture a value with use
Your task

Make scaleAll() pass all 5 checks. Run your code as often as you like, then check your answer.

exercise.phpSaved in this browserPHP 8.5
CONSOLE & CHECKS● Ready

Ready when you are

Your output will appear here.
Make it work. Then make it pass.

PHP loads on your first run. Each check starts fresh. Your code stays in this browser; clearing site data removes your progress. A check or the task looks wrong? Report a problem with this exercise.