関数内関数
PHPのマニュアルみてたら、こんなのがあった。今の今まで、ものすごい勢いで見逃してた。いまさらだけども、知らんかったなあこれ、できたんだ〜。コンパイル言語っぽい書き方だって気がしてたから、phpでできるとは思ってなかった。*1
pascal(というかDelphi言語)で、関数内関数はよく使ってた。
メソッド内で冗長にならざるを得ない箇所があり、privateで外出しするほどフレキシブルな処理でもないときに、関数内関数が多いに役に立った(あとは再帰とか)。クロージャも自分の中では、要するに関数内関数みたいなもんだろ?って始めは理解していた(というかこの理解の仕方は未だ変わっていないのだが)。
create_functionするよりもこっちのほうがおれは好きだな。懐かしい書き方だったので思わずメモる。
が、こんな気になるトピックも。
公式サイトのマニュアルに載っている、関数内関数ですが…
http://www.php.net/manual/ja/language.functions.php#AEN4977以下のスクリプトを作成し(/home/www/hoge.phpとしましょう)、
');
}
bar();
}foo(); // ←1回目
foo(); // ←2回目
?>
実行してみた。
$ php -v PHP 5.2.2 (cli) (built: May 30 2007 10:42:19) Copyright (c) 1997-2007 The PHP Group Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies $ php hoge.php bar<br> Fatal error: Cannot redeclare bar() (previously declared in /home/admin/hoge.php:4) in /home/admin/hoge.php on line 3
あちゃー、変わってないや。それが仕様ってことなんか。関数内関数を定義した関数は、一回しか呼べないってことになるんかい。
だが、そこはPHP。こうすれば回避可能だそうだ。
<?php function foo(){ if (!function_exists('bar')) { function bar(){ echo('bar<br>'); } } bar(); } foo(); // ←1回目 foo(); // ←2回目 ?>
ここらへんはまさにLLって感じだな。覚えとこう。下記は実行結果。
$ php hoge.php bar<br>bar<br>
だけど、LLにはクロージャがよく似合う。phpもcreate_functionじゃなくて、クロージャを実装するべきだ。perlみたく、代入 or 定義すると、関数のポインタ(リファレンスか)が返ってくるようなヤツ。
昔、perlでクロージャを使ったとき、スコープの関係でメモリリーク起こしたことあったけれど、今となっては懐かしき思ひ出。
(追記)
JavaScriptは完璧だった。
<html> <head> <script> function foo(){ function bar(){ document.write('bar<br>'); } bar(); } foo(); foo(); </script> </head> </html>
*1:JavaScriptでも同様な書き方ができる