あっぽログ
← 記事一覧に戻る

PHPのClosure(無名関数)を使いこなす:基本から活用パターンまで徹底解説

Closureとは何か

PHPにおける Closure(クロージャ) とは、名前を持たない「無名関数」のことです。変数に代入したり、他の関数へ引数として渡したり、関数の戻り値として返したりすることができます。

PHP 5.3 で導入され、PHP 7・8 と進化を重ねながら今日のPHP開発で欠かせない機能となっています。

<?php

// 変数に代入するシンプルなClosure
$greet = function (string $name): string {
    return "こんにちは、{$name}さん!";
};

echo $greet("田中"); // こんにちは、田中さん!

通常の関数と同じようにパラメータや戻り値の型宣言を付けることができます。


useキーワードで外側のスコープを取り込む

通常の関数と大きく異なるのが、use キーワードを使って外側のスコープにある変数を取り込める点です。

<?php

$prefix = "【お知らせ】";

$buildMessage = function (string $text) use ($prefix): string {
    return $prefix . $text;
};

echo $buildMessage("本日は休業です。");
// 【お知らせ】本日は休業です。

デフォルトでは値渡しです。クロージャの生成時点の値がコピーされます。

<?php

$count = 0;

$increment = function () use ($count): void {
    echo $count . "\n"; // 常に 0 が出力される
};

$count = 10;
$increment(); // 0

参照渡しにしたい場合は & を付けます。

<?php

$count = 0;

$increment = function () use (&$count): void {
    $count++;
};

$increment();
$increment();
echo $count; // 2

アロー関数(Arrow Function)

PHP 7.4 で追加された アロー関数 は、fn キーワードを使ったよりシンプルな書き方です。外側のスコープの変数を 自動的に値渡しで取り込む 点が特徴です。

<?php

$multiplier = 3;

$triple = fn(int $n): int => $n * $multiplier;

echo $triple(5); // 15

use を明示的に書く必要がなく、単一式であればスッキリ記述できます。複数行の処理が必要な場合は従来の無名関数を使いましょう。


実践的な活用パターン

コールバックとして渡す

array_maparray_filter などの配列関数と組み合わせるのが典型的な使い方です。

<?php

$prices = [100, 250, 80, 430, 60];

// 100円以上の価格だけを抽出
$filtered = array_filter($prices, fn(int $price): bool => $price >= 100);

// 10%引きに変換
$discounted = array_map(fn(int $price): int => (int)($price * 0.9), $filtered);

print_r($discounted);
// Array ( [0] => 90 [1] => 225 [3] => 387 )

クロージャを返す関数(ファクトリパターン)

クロージャを返す関数を作ることで、動的に振る舞いを変えた関数を生成できます。

<?php

function makeGreeter(string $language): Closure
{
    return match ($language) {
        'en' => fn(string $name): string => "Hello, {$name}!",
        'fr' => fn(string $name): string => "Bonjour, {$name}!",
        default => fn(string $name): string => "こんにちは、{$name}さん!",
    };
}

$greetJa = makeGreeter('ja');
$greetEn = makeGreeter('en');

echo $greetJa("佐藤"); // こんにちは、佐藤さん!
echo $greetEn("Smith"); // Hello, Smith!

Closure::bindToでオブジェクトに束縛する

Closure::bindTo() を使うと、クロージャを特定のオブジェクトに紐付けて $this を使えるようにできます。

<?php

class User
{
    private string $name;
    private int $age;

    public function __construct(string $name, int $age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}

$getProfile = function (): string {
    return "{$this->name}({$this->age}歳)";
};

$user = new User("山田", 28);
$bound = Closure::bind($getProfile, $user, User::class);

echo $bound(); // 山田(28歳)

クラスの外部からプライベートプロパティにアクセスできる強力な機能です。テストやデバッグ目的で使われることがあります。


静的クロージャ

static を付けると $this を持たない 静的クロージャ を定義できます。オブジェクトに束縛されないため、不用意なメモリの保持を防ぎます。

<?php

$add = static function (int $a, int $b): int {
    return $a + $b;
};

echo $add(3, 7); // 10

オブジェクトコンテキストが不要な場合は積極的に static を付けるとコードの意図が明確になります。


まとめ

機能説明
無名関数function で定義、変数や引数として利用可能
use外側スコープの変数を値渡しまたは参照渡しで取り込む
アロー関数fn による短縮構文、外側変数を自動取り込み
Closure::bindオブジェクトへの束縛で $this を使えるように
静的クロージャstatic$this を持たないクロージャを定義

Closure を使いこなすことで、コールバック処理・ファクトリパターン・遅延評価など様々な場面でコードをよりシンプルかつ柔軟に書けるようになります。ぜひ日常の実装に取り入れてみてください。

← 記事一覧に戻る