PHPのクロージャ(Closure)は、名前を持たない関数、いわゆる無名関数(Anonymous Function)のことです。変数に代入したり、他の関数の引数として渡したりできるため、コールバック処理や動的な関数生成に最適です。
クロージャは use キーワードを使って外部の変数を取り込む(キャプチャする)ことができ、関数型プログラミングのスタイルをPHPで実現する基盤となる機能です。
基本的な使い方
function キーワードの後に名前を付けずに定義し、変数に代入します。
<?php
// 無名関数を変数に代入
$greet = function($name) {
return "こんにちは、{$name}さん!";
};
echo $greet("田中") . "\n";
echo $greet("佐藤") . "\n";
こんにちは、田中さん!
こんにちは、佐藤さん!
通常の関数と異なり、定義の末尾にセミコロン ; が必要です。これは無名関数の定義が式(代入文の右辺)であるためです。変数 $greet を通じて、通常の関数と同じように呼び出せます。
useによる変数のキャプチャ
クロージャの外側にある変数を取り込むには use キーワードを使います。
<?php
$taxRate = 0.10;
$calcPrice = function($price) use ($taxRate) {
return $price * (1 + $taxRate);
};
echo $calcPrice(1000) . "\n";
echo $calcPrice(500) . "\n";
// useは値のコピー(デフォルト)
$taxRate = 0.08;
echo $calcPrice(1000) . "\n"; // まだ0.10のまま
1100
550
1100
デフォルトでは use は値のコピーを取り込みます。クロージャ定義後に外部変数を変更しても、クロージャ内の値は変わりません。参照渡しで取り込みたい場合は use (&$taxRate) のように & を付けます。
参照渡しのuse
<?php
$count = 0;
$increment = function() use (&$count) {
$count++;
};
$increment();
$increment();
$increment();
echo "カウント: {$count}\n";
カウント: 3
&$count により参照渡しでキャプチャしているため、クロージャ内での変更が外部の $count に反映されます。
コールバック関数として使う
クロージャは array_map() や array_filter() などのコールバックとして頻繁に使われます。
<?php
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 偶数だけフィルタリング
$evens = array_filter($numbers, function($n) {
return $n % 2 === 0;
});
echo "偶数: " . implode(", ", $evens) . "\n";
// 各要素を2乗
$squared = array_map(function($n) {
return $n ** 2;
}, $numbers);
echo "2乗: " . implode(", ", $squared) . "\n";
// usortでカスタムソート
$users = [
["name" => "田中", "age" => 30],
["name" => "佐藤", "age" => 25],
["name" => "鈴木", "age" => 35],
];
usort($users, function($a, $b) {
return $a["age"] - $b["age"];
});
foreach ($users as $u) {
echo "{$u['name']}({$u['age']}歳) ";
}
echo "\n";
偶数: 2, 4, 6, 8, 10
2乗: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100
佐藤(25歳) 田中(30歳) 鈴木(35歳)
実用的な例
<?php
// 関数を返す関数(高階関数)
function multiplier(int $factor): Closure {
return function(int $n) use ($factor): int {
return $n * $factor;
};
}
$double = multiplier(2);
$triple = multiplier(3);
echo $double(5) . "\n"; // 10
echo $triple(5) . "\n"; // 15
10
15
クロージャは内部的に Closure クラスのインスタンスです。Closure::bind() や Closure::fromCallable() などのメソッドも利用できます。型宣言では Closure 型または callable 型で受け取れます。
use で参照渡しを使うと、クロージャの外部からも値が変更される可能性があり、バグの原因になりやすいです。状態を持つクロージャが必要な場合はクラスの利用も検討してください。
まとめ
- クロージャは名前のない関数で、変数に代入したり引数として渡せる
useキーワードで外部変数をキャプチャでき、デフォルトは値コピーuse (&$var)で参照渡しキャプチャも可能array_map()やarray_filter()のコールバックに最適- 高階関数(関数を返す関数)の実装にも使える