hnwの日記

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.phpMacOSX 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などが実装されており、アプリケーションとしてはWordPressDrupalなども動いているようです。一定以上の互換性は確保されていそうです。


一方で、「==」の処理を少し試してみると本家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回しか回らないですよね。

まとめ

Quercusは古くからあるPHP実装なので期待していたんですが、イマイチ勢いも徹底性も欠けているような印象を受けました。余計なお世話かもしれませんが、もう少しオープンソースコミュニティ形成に力を入れた方がいいんじゃないでしょうか。GitHubでissueを受け付けるだけでも全然違うと思うんですよ。


とはいえ、一定以上マトモに動くPHP実装は貴重です。Resinと一緒にバージョンアップは続いているわけですから、今後も選択肢の一つとして頑張って頂きたいですね。