無名関数(クロージャ)
無名関数(クロージャ)とは、名前を付けずに作成した関数のことである。無名関数で作成した関数は、変数に代入し直接実行したり、別の関数の引数にcallbackとして渡したりして使うことができる。無名関数と同様の機能を実現するために、従来はcreate_functionが利用されていた。
利用例1 — 直接実行
引数で与えられた値を2倍にして返す関数の例。
1 2 3 4 5 | $doubler = function($i){return $i*2;}; echo $doubler(2); 実行結果 4 |
このように、作成したクロージャを直接実行することもあるが、作成したクロージャはコールバックとして利用することが多い。
利用例2 — コールバックとして実行
配列から奇数の値だけを抽出。奇数かどうかを判定する無名関数を作成し、array_filterで該当要素だけを抽出している。
1 2 3 4 5 6 7 8 9 | $isEven = function ($i){return $i % 2 == 0;}; $evenNumbers = array_filter( array(1, 2, 3), $isEven); print_r($evenNumbers); 実行結果 Array ( [1] => 2 ) |
$isEvenという変数に代入せず下記のようにも記述できる。
1 2 3 4 5 6 7 8 9 10 11 | $evenNumbers = array_filter( array(1, 2, 3), function ($i){return $i % 2 == 0;} ); print_r($evenNumbers); 実行結果 Array ( [1] => 2 ) |
create_functionとの比較
PHP5.2以前から実装されていたcreate_function関数を使うと、無名関数(クロージャ)と類似の機能を実現できる。機能面での差は小さいが、create_functionと、無名関数(クロージャ)の実装は大きく異なる。
記述の比較
create_functionでは、関数の中身を文字列で記述することに注意。
無名関数(クロージャ)
1 2 3 4 |
create_function
1 2 3 4 |
内部処理の比較
無名関数(クロージャ)
クロージャオブジェクが生成される。
1 2 3 4 5 6 7 8 |
create_function
関数が生成され、その関数名が戻り値となる。名前衝突を防止するため、1文字目は特殊文字。
1 2 3 4 |
外部の変数は見えない
通常の関数と同様、特に指定しないと、グローバル変数を参照することはできない。
1 2 3 4 5 | $j = 1; $adder = function ($i) {return $i + $j;}; echo $adder(2); 実行結果 2 |
useを使う
引数にUseを指定すると外部の変数を参照することができます。ただし、Useで指定した値が評価されるのは関数を定義した時。
1 2 3 4 5 6 7 | $j = 1; $adder = function ($i) use ($j){return $i + $j;}; echo $adder(2); $j = 2; echo $adder(2); 実行結果 33 |
Useで参照を渡すようにすると、関数定義後の値の変化が反映される。値渡しにするのか、参照渡しにするのかで挙動が変わるので注意。
1 2 3 4 5 6 7 | $j = 1; $adder = function ($i) use (&$j){return $i + $j;}; echo $adder(2); $j = 2; echo $adder(2); 実行結果 34 |
もちろん、通常の関数と同様にglobal指定をしたり$GLOBALS変数を参照することで、外部の変数を参照できる。
1 2 3 4 5 6 7 | $j = 1; $adder = function ($i){global $j;return $i + $j;}; echo $adder(2); $j = 2; echo $adder(2); 実行結果 34 |
無名関数を使った再帰呼び出し
useを使うと再帰も組めます。f(n) = 0, f(n) = f(n-1) + n, でf(10)を求めるプログラムは以下の通り。
1 2 3 4 5 6 7 8 9 10 | $sum = function ($i) use (&$sum){ if($i == 0){ return 0; }else{ return $sum($i - 1) + $i; } }; echo $sum(10); 実行結果 55 |
__invokeメソッド
PHP5.3では、__invokeというマジックメソッドが存在する。このメソッドが定義されているオブジェクトは、メソッドとして呼び出すことができる。無名関数(クロージャ)は__invokeメソッドをもったオブジェクトなのだ。
1 2 3 4 5 6 7 8 9 10 | class invocable{ public function __invoke(){ echo "invoked"; } } $obj = new invocable(); $obj(); 実行結果 invoked |
参考
http://idocsq.net/page/94
http://nonn-et-twk.net/twk/php5.3-lambda
[…] PHP5.3/クロージャのページを加筆修正。文才の無さにヘコミ中。 […]