A closure is a function that carries some outside variables with it. In PHP, every anonymous function is an object of the Closure class, and you pick the outside variables with use.
<?php
$greeting = "Hello";
$greet = function (string $name) use ($greeting): string {
return "$greeting, $name!";
};
echo $greet("Asha");
Hello, Asha!
Without use ($greeting), the function could not see $greeting, because functions in PHP have their own scope.
The value is copied when the closure is created
<?php
$count = 1;
$show = function () use ($count) {
echo "Count is $count\n";
};
$count = 99; // changed after the closure was made
$show();
Count is 1
The closure kept the value 1.
use by reference
Add & to see later changes, and to let the closure change the outside variable.
<?php
$total = 0;
$add = function (int $n) use (&$total): void {
$total += $n;
};
$add(5);
$add(10);
echo $total;
15
A counter factory
<?php
function makeCounter(): callable
{
$count = 0;
return function () use (&$count): int {
return ++$count;
};
}
$a = makeCounter();
$b = makeCounter();
echo $a() . $a() . $a() . " ";
echo $b();
123 1
Each counter has its own private $count. That is the main power of closures: private state without a class.
Closures inside classes
A closure created inside a method automatically has access to $this.
<?php
class Cart
{
private array $items = ["Pen", "Book"];
public function printer(): callable
{
return function (): void {
echo count($this->items) . " items";
};
}
}
$print = (new Cart())->printer();
$print();
2 items
Static closures
If a closure does not need $this, mark it static. It will not keep the object alive.
<?php
$double = static fn(int $n): int => $n * 2;
echo $double(21);
42
Closure vs arrow function
function () use (...) | fn() => | |
|---|---|---|
| Outside variables | Listed with use | Captured automatically |
| Body | Many statements | One expression |
| By reference | Yes, with & | No |
Why this matters in WordPress
add_action("init", function () { ... });. You will see that in WordPress Hooks.