Reading — step 1 of 6
Learn
PHP closures are first-class values — assignable, passable, returnable. But they capture variables differently from JavaScript or Python.
Anonymous functions
$double = function(int $n): int {
return $n * 2;
};
echo $double(5); // 10
A Closure is an instance of the built-in \Closure class.
The use clause — capturing
Unlike JS and Python, PHP closures DON'T capture parent variables automatically. You must list them with use:
$factor = 3;
$multiply = function(int $n) use ($factor): int {
return $n * $factor;
};
echo $multiply(7); // 21
Capture is by value by default — it's a snapshot at definition time:
$x = 10;
$f = function() use ($x) { return $x; };
$x = 99;
echo $f(); // 10 — captured the original
For by-reference, prefix with &:
$x = 10;
$f = function() use (&$x) { return $x; };
$x = 99;
echo $f(); // 99 — sees the live $x
Arrow functions (PHP 7.4+)
Shorter syntax, AUTOMATIC capture by value of all needed outer variables:
$factor = 3;
$multiply = fn(int $n) => $n * $factor; // no `use` clause needed
echo $multiply(7); // 21
Limitations:
- Single expression only (no statements)
- No way to capture by reference
- Always returns the expression's value
Great for short callbacks: array_map(fn($x) => $x * 2, $nums).
Closures with array_* functions
The sweet spot for closures:
$evens = array_filter([1,2,3,4,5], fn($n) => $n % 2 === 0); // [2, 4]
$doubled = array_map(fn($n) => $n * 2, [1,2,3]); // [2, 4, 6]
$total = array_reduce([1,2,3,4], fn($carry, $n) => $carry + $n, 0); // 10
bindTo and binding $this
Closures can be bound to an object so $this works inside:
class User {
public string $name = 'Ada';
}
$greet = function() { return "Hi, $this->name"; };
$bound = Closure::bind($greet, new User(), User::class);
echo $bound(); // Hi, Ada
Useful for adding methods to objects after the fact — frameworks lean on this.
Common mistakes
- Forgetting
use— variables from the parent scope are NOT auto-captured in regular closures.function() { return $x; }won't see outer $x. - Capturing by value when you wanted by reference —
use ($x)snapshots; subsequent changes to outer $x are invisible inside. - Assuming arrow functions can have a body — they're expression-only.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…