Closures and the use Keyword

Anonymous functions that capture variables from the surrounding scope with use — by value, or by reference for shared mutable state.

A closure is an anonymous function you can store in a variable, pass around, and return. Unlike a named function, it can close over variables from where it was defined — but you must list them explicitly with use.

By value vs by reference

use ($x) captures a snapshot of $x at definition time. use (&$x) captures a reference, so changes inside and outside the closure stay in sync.

<?php
$greeting = 'Hi';
$sayHi = function(string $name) use ($greeting): string {
    return "$greeting, $name!";
};
echo $sayHi('Sam'); // Hi, Sam!

You can also rebind a closure's $this with Closure::bind(), which is how some frameworks add methods to objects on the fly.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Capture a $taxRate variable from the outer scope with use to create a reusable price-formatting closure.
  • Pass a closure to usort() that captures an outer $sortField to sort records by a runtime-chosen column.
  • Store an event handler as a closure in an array and invoke it later when the event fires.

More examples

Closure capturing with use

use($taxRate) copies $taxRate into the closure's scope; changing $taxRate outside does not affect the closure.

Example · php
<?php
$taxRate = 0.08;

$applyTax = function (float $price) use ($taxRate): float {
    return round($price * (1 + $taxRate), 2);
};

echo $applyTax(100.00); // 108.0
echo $applyTax(49.99);  // 53.99

Capture by reference with use &

use (&$log) captures by reference so each call appends to the same $log array in the outer scope.

Example · php
<?php
$log = [];

$logger = function (string $message) use (&$log): void {
    $log[] = date('H:i:s') . " $message";
};

$logger('Start');
$logger('Processing');
$logger('Done');

print_r($log);

Closure bound to an object

Closure::bind() attaches a closure to an object so $this refers to that object, enabling white-box testing of private state.

Example · php
<?php
class Counter {
    private int $count = 0;
}

$increment = Closure::bind(
    function (int $by = 1): void { $this->count += $by; },
    new Counter(),
    Counter::class
);

$increment();
$increment(5);

$get = Closure::bind(
    function (): int { return $this->count; },
    (function () use ($increment) {
        // grab the bound object
        return null;
    })(),
    Counter::class
);

// Simpler demo:
$c  = new Counter();
$fn = Closure::bind(fn() => $this->count, $c, Counter::class);
echo $fn(); // 0

Discussion

  • Be the first to comment on this lesson.