勢いに任せてVM・構文解析器・コア関数をハックして以下の機能を実装してみました。
- php-5.2.5-rsky-071126.patch 最初のリリース。(PHP 5.2.5用パッチ)
- php-5.2.5-rsky-071126-2.patch 角括弧の連想配列リテラルでは => でなくコロンを使うように変更。
- php-5.2.5-rsky-071127.patch 無名関数内で無名関数を定義できなかったのを修正。
- php-5.2.5-rsky-071127-2.patch メモリリークを修正。
- php-5.2.5-rsky-071127-3.patch ReflectionFunction::exportで落ちるのを修正。
Zend Extensionにするのは面倒なので、まずはパッチとして公開してみます。このパッチを当ててPHPをビルドする際に zend_language_parser.c と zend_language_parser.h を再生成するので、Bisonの特定のバージョンがインストールされていないといけません。PHP: Unix システムへのインストール - Manualにあるものを揃えてください。僕の場合は bison 1.75, flex 2.5.4, re2c 0.9.12, autoconf 2.13, automake 1.5, libtool 1.4.3 を /opt/php/build 以下にインストールし、PHPのビルド時は /opt/php/build/bin をコマンド検索パスの先頭にしています。
無名関数リテラル
http://pastebin.ca/400871を参考に実装しました。
サンプル:
<?php $array = range(1, 5); shuffle($array); print_r($array); usort($array, function($a,$b){return $a-$b;}); print_r($array); // 参照を返す無名関数も書けるけど、"function" と "(" の間に "&" があるのがキモい $lambda = function&(){ static $a = []; return $a; }; // ブレースの後にセミコロンをつけないとエラーになるので注意 $a = &$lambda(); $a[] = 1; print_r($a); $b = &$lambda(); $b[] = 2; print_r($b); var_dump($a === $b);
結果:
Array ( [0] => 3 [1] => 1 [2] => 4 [3] => 2 [4] => 5 ) Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 ) Array ( [0] => 1 ) Array ( [0] => 1 [1] => 2 ) bool(true)
角括弧による配列リテラル
相変わらずキーを指定するときは"=>"が必要ですが、arrayを書かずにすむだけ楽かと。
サンプル:
<?php var_dump([0, 1, 2]); var_dump(['foo': 'orange', 'bar': 'apple', 'baz': 'lemon']);
結果:
array(3) { [0]=> int(0) [1]=> int(1) [2]=> int(2) } array(3) { ["foo"]=> string(6) "orange" ["bar"]=> string(5) "apple" ["baz"]=> string(5) "lemon" }
Callable Object
Callableインターフェイスを実装したクラスのインスタンスを関数のように扱うことができます。Callableインターフェイスを実装するクラスはpublicな関数callを実装しなければなりません。サンプルでは単にHello, Worldを出力するだけですが、任意の引数をとったり、$thisにアクセスしたり、コールバック関数として引数にすることも可能ですcall_user_func, call_user_func_arrayには対応していますが、usortやpreg_replace_callaback等には使えませんでした。
サンプル:
<?php class Proc implements Callable { public function call() { echo "Hello, World!\n"; } } $proc = new Proc; $proc();
結果:
Hello, World!