PHPの壁に当たったとき
- 素直にそこは代わりのものを使うのがよく訓練されたぺちぱー
- よーしおじさんextension書いちゃうぞーとなるのがぺくらー
- 本体へのパッチを書くのが僕
- パッチがスルーされて切ないのも僕
- ならば既成事実を作ってやろうとコンパイラを差し換えるzend extensionを作る決意をしたのも以下略
zend extension版はこんな感じになる予定です。
- zend_complile.c, zend_langage_parser.c, zend_language_scanner.c をベースに独自のコンパイラを作る。
- 関数ポインタzend_compile_fileとzend_compile_stringを差し換える。
- do_bind_functionの絡みで、zend_opcode_handlersのZEND_DECLARE_FUNCTION_SPEC_HANDLERに相当する部分を独自のハンドラに置き換える。
グローバル変数の関数ポインタを置き換えるだけだし、ソースコードの99%以上はオリジナルと同じなので、zend extensionでなく普通のextensionでも構わないかもしれません。ということは、実行時に動的にコンパイラを切り替えることも可能な気がしてきました。
ところで、RSKitの次のバージョンでは関数を複製し、スタティック変数の値をアクティブなスコープから取り込むencloseメソッドを実装します。これを無名関数と組み合わせると、疑似的にクロージャが実現できます。
<?php function f($a, $b) { return RSKit::enclose(function($c){ static $a, $b; $d = $a + $c; $e = $b - $c; return $d * $d + $e * $e; }); } $f = f(1, 2); $g = f(3, 4); var_dump($f(1), $g(1)); var_dump($f(2), $g(2));
結果:
int(5) int(25) int(4) int(29)
ZendEngineでクロージャをサポートしようとすると、コンパイラだけでなく実行エンジンにもかなり手を入れねばならず、仕様も実装もgdgdになりかねないので、拡張モジュールで疑似的なものを実現した方が無難と考えています。