PHPのJava実装であるQuercusをCLIで動かしてみた
今日は有名PHP実装の一つであるQuercusを紹介します。これはJavaサーブレットコンテナResinを開発しているCaucho社が開発しているもので、当然のことながらJava環境で動作します。既存のPHPコードを動かすのにJava環境のノウハウや資産が生かせれば良いところ取りができるわけで、野心的なプロジェクトだと言えるでしょう。前回記事「MacOSX上で.NET環境向けPHPコンパイラPhalangerを動かしてみた」で紹介したPhalangerと似た発想ですね。
今回はコマンドラインからQuercus単体で使ってみました。いちいちアプリケーションサーバをセットアップしなくても気軽に試せるのは嬉しいところです。
QuercusをCLIから動かす
Quercusには「com.caucho.quercus.CliQuercus」というコマンドラインインターフェース用のクラスが提供されています。これを使ってみましょう。
まずはQuercusのwarファイルからjarファイルを取り出します。Quercusホームページ下部の「Downloads」から「quercus-4.0.39.war」をダウンロードしてwarを展開します。
$ mkdir -p /tmp/quercus $ cd /tmp/quercus $ unzip -x $HOME/Downloads/quercus-4.0.39.war WEB-INF/lib/quercus.jar
ここで取り出したquercus.jarだけでPHPスクリプトが動きます。
$ echo '<?php var_dump(PHP_INT_MAX);' > int_max.php $ java -cp WEB-INF/lib/quercus.jar com.caucho.quercus.CliQuercus int_max.php int(9223372036854775807)
ベンチマークテスト
では、このCLI版のQuercusとPHPとの速度を比較してみましょう。PHPソースコード付属のベンチマークテストZend/bench.phpをMacOSX 10.9上で実行してみました。
PHP7 | PHP 5.6 | Phalanger | Quercus | |
---|---|---|---|---|
simple | 0.094 | 0.112 | 0.069 | 0.195 |
simplecall | 0.028 | 0.116 | 0.019 | 0.179 |
simpleucall | 0.054 | 0.112 | 0.021 | 0.212 |
simpleudcall | 0.053 | 0.116 | 0.021 | 0.229 |
mandel | 0.314 | 0.304 | 0.387 | 0.858 |
mandel2 | 0.347 | 0.356 | 0.584 | 0.769 |
ackermann(7) | 0.078 | 0.140 | 0.044 | 0.264 |
ary(50000) | 0.008 | 0.023 | 0.025 | 0.097 |
ary2(50000) | 0.008 | 0.019 | 0.017 | 0.044 |
ary3(2000) | 0.136 | 0.152 | 0.338 | 0.394 |
fibo(30) | 0.181 | 0.374 | 0.151 | 0.609 |
hash1(50000) | 0.017 | 0.029 | 0.116 | 0.114 |
hash2(500) | 0.017 | 0.035 | 0.073 | 0.062 |
heapsort(20000) | 0.067 | 0.092 | 0.116 | 0.310 |
matrix(20) | 0.069 | 0.086 | 0.136 | 0.164 |
nestedloop(12) | 0.156 | 0.199 | 0.115 | 0.256 |
sieve(30) | 0.041 | 0.089 | 0.114 | 0.151 |
strcat(200000) | 0.010 | 0.013 | 0.013 | 0.041 |
Total | 1.677 | 2.365 | 2.356 | 4.947 |
Phalangerも含めて比較してみましたが、Quercusが一番遅いという結果になりました。CLI版では本気を出してくれないのかもしれません。Caucho社による文書「Faster PHP Through Java」(PDF)などを見るとPHPより断然速そうなんですけどね…。
ちなみに、Javaのバージョンは下記の通りです。
$ java -version java version "1.6.0_65" Java(TM) SE Runtime Environment (build 1.6.0_65-b14-462-11M4609) Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-462, mixed mode)
互換性
現在最新版のQuercus 4.0.39ではPHP 5.4相当の機能を持っており、名前空間、配列の短縮構文やtraitなどがサポートされています。エクステンションもPDO、curl、mbstring、SimpleXMLなどが実装されており、アプリケーションとしてはWordPressやDrupalなども動いているようです。一定以上の互換性は確保されていそうです。
一方で、「==」の処理を少し試してみると本家PHPとの違いが目につきました。たとえば下記のようなコードでPHPとは挙動が異なります。
<?php var_dump("0x"=="0"); // Quercus: true PHP: false var_dump(".1z"=="0.1"); // Quercus: true, PHP: false var_dump("1ee"==".1E1E"); // Quercus: true, PHP: false
実装をチラ見する
Quercusではソースコードがjarの形で提供されています。これを斜めに見てみました。
レキサ・パーサは手書きのようです(com/caucho/quercus/parser/QuercusParser.java)。修正やメンテでつらい気持ちになりそうです。
また、「==」の処理を追っていくと数値文字列かどうかを判定するメソッドが見つかりました(com/caucho/quercus/env/StringBuilderValue.java の getValueType())。ここは仕様として複雑なため正しく実装するのが難しい処理ですが、やや雑に実装されている印象です。特に次のコードは怖い先輩に詰められるレベルだと思いました。
if (ch == '.') { // XXX: this doesn't look right 2012-03-15 for (i++; i < len && '0' <= (ch = buffer[i]) && ch <= '9'; i++) { return ValueType.DOUBLE_CMP; } return ValueType.STRING; }
for文の内側でreturnしてるので、このループ絶対1回しか回らないですよね。