PHP で クロージャ さっきまでの無し
http://d.hatena.ne.jp/am11op/20070702/1183376369
↑前エントリがただの劣化コピーだってことに電車の中で気が付いた。
てことで、勝手にリベンジ。
その前に、closure の定義自体はとりあえず置いておいて、
自分が作ろうとしてる(欲しい)のは何なのか。
- 外側の変数を参照できる
- 使うその場で定義できる
↓ていうか、これ。
http://itpro.nikkeibp.co.jp/article/COLUMN/20050930/221971/?ST=oss
これができないのは、ただの callback 関数なんじゃないかと思うわけです。
で作ったのがこれ。
/* * closure を実現するための class */ class Closure { var $_args; var $_func; /** * @private */ function Closure($func, $args) { $this->_args = $args; $func = ereg_replace("^function\([^\)]*\) *\{", "", $func); $func = ereg_replace("\}$", "", $func); $this->_func = $func; } /** * @param $func string closure * @param $arg1 $mixed first object/var which is used in $func * @param $arg2 $mixed second object/var which is used in $func * ... */ function bind() { $args = func_get_args(); return new Closure(array_shift($args), $args); } /** * use this method to call closure */ function call() { $func = create_function('$args', $this->_func); $func($this->_args); } } // 以下、使用例 class Test{ function sayTest($int=0){ return 'this is a test.'; } } $obj = new Test; function piyo($bool, $obj) { if ($bool) { $obj['onSuccess']->call(); } else { $obj['onFailure']->call(); } } $hoge = "you know, "; $arr = array( 'onSuccess'=>Closure::bind("function(\$args){echo '$hoge'.\$args[0]->sayTest();}", &$obj), 'onFailure'=>Closure::bind("function(\$args){echo 'fail!';"), ); echo piyo(true, $arr); // you know, this is a test. echo piyo(false, $arr); // fail!
- Closure::bind の第一引数に closure を渡す
- closure 内の instance は全て $args とする
- $args に対応する instance を第二引数以降に渡す
- closure はダブルクォーテーションでくくる場合は、$args の前に「\」を付ける必要がある
- closure の頭に「function(\$args){」、尻に「}」が付いているが、これは closure であることを明示するためである
- どっちみち ereg_replace で削除されるので、はっきり言って必要ない
「\」がウザい場合は、クロージャをシングルクォーテーションで囲って、
普通の変数も引数に渡してクロージャ内から $args[n] として参照すればよいです。
ちょっとは closure ぽくなったでしょか。
PHP で クロージャ
※これ失敗でした。↓にもちょっとマシなやつ書いてます
http://d.hatena.ne.jp/am11op/20070702/1183392610
CakePHP 使ってたら、ものすごく closure 使いたくなった。
ググったら途中までやってる方達がいたので、
それパクって作ってみた。
↓途中までやってる方達
http://blog.xole.net/article.php?id=419
http://p0t.jp/mt/archives/2007/04/1byte.html
要は create_function を使えばよいわけだ。
closure.php
function closure($str) { $str = ereg_replace("^function\(\) *\{", "", $str); $str = ereg_replace("\}$", "", $str); $func =create_function('', $str); $func(); } function hoge($str, $func='') { echo $str; if ($func) { closure($func); } } echo hoge('こんにちわ。', "function() {echo 'クロージャだよ!';}");
実行結果
こんにちわ。クロージャだよ!
ものすごく使う気にならないのはなんでだ。
PHP で クロージャ失敗
http://d.hatena.ne.jp/am11op/20070702/1183376369
↑前エントリのクロージャもどきがものすごく使いたくならない理由がわかった。
function closure($str) { $str = ereg_replace("^function\(\) *\{", "", $str); $str = ereg_replace("\}$", "", $str); $func =create_function('', $str); $func(); } class Test{ function sayTest(){ echo 'test'; } } $obj = new Test; function piyo($bool, $obj='') { if ($bool) { closure($obj['onSuccess']); } else { closure($obj['onFailure']); } } $arr1 = array( 'onSuccess'=>'echo "OK!";', 'onFailure'=>'echo "NG!";', ); echo piyo(true, $arr1); // OK! echo piyo(false, $arr1); // NG! $arr2 = array( 'onSuccess'=>'function(){echo $obj->sayTest();}', // この時点で syntax error ); echo piyo(true, $arr2);
class とか instance 使った時点で閉じた空間じゃなくなるので、
こういうものはいくらそれっぽく作っても、
結局 closure とは呼べないだろうと思った。
- 結論
- 失敗例を増やしただけ