Skip to content
Closures and Binding
step 1/5

Reading — step 1 of 5

Learn

~1 min readClosures and Iterators

PHP closures are objects of class Closure. Unlike most languages, PHP requires you to explicitly capture outer variables with use.

<?php
$base = 10;

$add = function ($n) use ($base) {
    return $n + $base;
};

echo $add(5);    // 15
$base = 20;       // closure already captured 10
echo $add(5);    // still 15

Capture by reference with &:

$counter = 0;
$inc = function () use (&$counter) {
    $counter++;
};

$inc(); $inc(); $inc();
echo $counter;   // 3

Arrow functions (PHP 7.4+) auto-capture (by value):

$base = 10;
$add = fn($n) => $n + $base;     // implicitly use($base)
echo $add(5);   // 15

Much shorter for simple cases. Cannot use use with fn.

Closure::bind — change $this for a closure:

class Counter {
    private int $count = 0;
}

$reader = Closure::bind(
    fn() => $this->count,
    new Counter(),
    Counter::class
);

echo $reader();   // 0 — even though count is private

This lets you peek at private state for debugging or testing.

Closure::fromCallable — convert any callable (string method names, arrays, ...) to a Closure:

class Math {
    public static function add($a, $b) { return $a + $b; }
}

$add = Closure::fromCallable([Math::class, 'add']);
$add = Closure::fromCallable('Math::add');     // also works
echo $add(3, 4);   // 7

First-class callable syntax (PHP 8.1+) — even cleaner:

$add = Math::add(...);          // creates a Closure
$strlen = strlen(...);
$length = $strlen('hello');     // 5

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…