shin1x1 さんから、開始された PHP Advent Calendar jp 2010 16日目です。
書くTipsは、10分で考えて、5分で書ける内容で ok です。
とのことなので、さらっと。
PHP5.3から導入された無名関数って、5.2以前からある匿名関数とどうちがうの?ってお話。
PHP5.3から無名関数が利用できるようになりました。こんな感じで書けます。
$closure_echo = function( $s ){ echo $s . "\n"; }; $closure_echo('Hello World!');
preg_replace_callback なんかの第2引数に使う一時的な関数を定義するのに便利ですね。
PHP5.2までは、同様のことを create_function を使って、実現してました。
$anonymous_echo = create_function( '$s', 'echo $s."\n";' ); $anonymous_echo('Hello World!');
第1引数にパラメータを、第2引数に関数のコードを、それぞれ文字列として渡す必要があります。
コーディングしづらいこと、この上ないですね。
さて実際には、この無名関数と匿名関数は、どう違うのでしょう?
それぞれに割り当てられた変数を var_dump() してみるとわかります。
無名関数
var_dump($closure_echo); ↓ object(Closure)#1 (1) { ["parameter"]=> array(1) { ["$s"]=> string(10) "<required>" } }
匿名関数
var_dump($anonymous_echo); ↓ string(9) "lambda_1"
無名関数の実体は Closure オブジェクトですが、匿名関数の実体は "\0lambda_1"
と言う名前の関数なのです。
ちなみに匿名関数を複数定義すると、lambda_1, lambda_2, lambda_3… という風に連番で関数名が付けられていきます。
なので、匿名関数は作成した後に function_exists() 関数で存在を確認することもできます。
$anonymous_echo = create_function('$s', 'echo $s."\n";'); if (function_exists("\0lambda_1")) { $anonymous_echo('Hello World!'); }
しかも、この匿名関数を割り当てた変数を unset しても、関数定義自体は残ってるので call_user_func で呼び出すことも可能です。
$anonymous_echo = create_function('$s', 'echo $s."\n";'); unset($anonymous_echo); if (is_callable("\0lambda_1")) { call_user_func("\0lambda_1", ''Hello World!''); }
もちろん、無名関数は実体が Closure オブジェクトなんで、こんなハレンチなことはできません。
他に違いはあるでしょうか?
無名関数では、use を使って親のスコープから変数を引き継ぐことができます。
$count = 0; $closure = function() use ( &$count ) { echo $count++ . "\n"; }; $closure(); $closure(); $closure();
↓
0 1 2
もちろん use を使って自分自身を渡せば再帰処理もできます。
$fib = function( $n ) use( &$fib ) {
if ( $n < 2 ) {
return $n;
} else {
return $fib( $n -1 ) + $fib( $n -2 );
}
};
echo $fib(10);[/php]
再帰のサンプルと言えば、フィボナッチ。
The Lazy Rule of Thirds | Jake Garn Photography
ってことで PHP Advent Calendar jp 2010 16日目おしまい。
明日は koyhoge さんです。