ログイン



無名関数(クロージャ)

無名関数(クロージャ)とは、名前を付けずに作成した関数のことである。無名関数で作成した関数は、変数に代入し直接実行したり、別の関数の引数に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
$evenNumbers = array_filter(
    array(1, 2, 3),
    function ($i){return $i % 2 == 0;}
);

create_function

1
2
3
4
$evenNumbers = array_filter(
    array(1, 2, 3),
    create_function(\'$i\', \'return $i % 2 == 0;\')
);

内部処理の比較

無名関数(クロージャ)
クロージャオブジェクが生成される。

1
2
3
4
5
6
7
8
var_dump(function ($i){return $i % 2 == 0;});
object(Closure)#1 (1) {
["parameter"]=>
array(1) {
["$i"]=>
string(10) "<required>"
}
}

create_function
関数が生成され、その関数名が戻り値となる。名前衝突を防止するため、1文字目は特殊文字。

1
2
3
4
var_dump(
    create_function(\'$i\', \'return $i % 2 == 0;\')
);
string(9) "�lambda_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

One Response to “無名関数(クロージャ)”

  1. […] PHP5.3/クロージャのページを加筆修正。文才の無さにヘコミ中。 […]

Leave a Reply