Closures & Anonymous Functions
debt(d3/e3/b3/t7)
Closest to 'default linter catches the common case' (d3). Tools listed in detection_hints (rector, phpcs, php-cs-fixer) can detect verbose closures that could be arrow functions, and static analysis can catch some use() issues. However, the core mistake of forgetting to capture a variable often only surfaces at runtime as an undefined variable notice, pushing toward d5. Settling at d3 because the tooling ecosystem does catch the common patterns.
Closest to 'simple parameterised fix' (e3). The quick_fix indicates using fn() => arrow functions or Closure::fromCallable() — these are localized replacements within a single file. Fixing a forgotten use() clause or switching from value to reference capture is a one-line change (e1), but refactoring verbose closures to arrow functions across a component is a small but multi-line refactor (e3).
Closest to 'localised tax' (b3). Closures are foundational to array_map, array_filter, usort and callback APIs, so they touch many parts of a codebase. However, each closure is self-contained — a poor closure choice doesn't poison the architecture, it just adds friction locally. The applies_to shows broad context (web, cli, queue-worker) but the structural weight remains component-level, not system-defining.
Closest to 'serious trap' (t7). The misconception field explicitly states that PHP closures do NOT automatically capture variables from enclosing scope — unlike JavaScript where closures capture everything. A developer coming from JavaScript (the most common closure mental model) will guess wrong every time. This directly contradicts how a similar concept works in another major language, making it a t7 serious trap.
Also Known As
TL;DR
Explanation
PHP closures (anonymous functions) are instances of the Closure class, assignable to variables and passable as arguments. They capture outer-scope variables explicitly via use ($var) by value or use (&$var) by reference. In PHP 5.4+, $this is available inside closures defined in a class method. Arrow functions (PHP 7.4+) automatically capture outer scope by value without an explicit use clause. Closures are fundamental to array functions (array_map, usort), event callbacks, and middleware patterns.
Common Misconception
Why It Matters
Common Mistakes
- Forgetting to capture outer variables with use() — closures do not inherit the parent scope automatically.
- Capturing by value (use ($var)) when you need by reference (use (&$var)) to modify the outer variable.
- Using $this inside a closure defined outside a class — bind the closure to an object if needed.
- Creating closures in tight loops and ignoring the overhead — arrow functions (fn) are lighter for simple expressions.
Code Examples
$multiplier = 3;
$fn = function($n) {
return $n * $multiplier; // $multiplier is undefined here
};
$multiplier = 3;
$fn = function($n) use ($multiplier) {
return $n * $multiplier;
};
// Or with arrow function (PHP 7.4+):
$fn = fn($n) => $n * $multiplier;