Hatena::ブログ(Diary)

hnwの日記 このページをアンテナに追加 RSSフィード

[プロフィール]

2014年11月15日(土) HHVM 3.3.1とPHP 5.6.2の==の違いを調べてみた このエントリーを含むブックマーク このエントリーのブックマークコメント

PHPJITコンパイラ実装であるHHVMが最近話題ですね。本家より高速というふれこみですし、Facebookが開発・実運用している実績もあるわけですから、導入を検討されている方も多いのではないでしょうか。


とはいえ、特に商用環境に導入するとなると互換性がどこまで確保できているかも重要です。現時点でも実運用に耐える程度の互換性はあるはずですが、僕は非常に保守的な人間なので、HHVMが互換性にどこまでこだわっているのかに興味があります。


今回、==演算子に絞ってHHVMとPHPの挙動を調べてみたところ、2点の違いを見つけたので紹介します。比較にはUbuntu14.04上のpre build版HHVM 3.3.1と自前ビルドしたPHP 5.6.2を利用しました。


浮動小数点数と16進数値文字列の比較が浮動小数点比較されない

PHPで数値と数値文字列を==で比較した場合は数値として比較されます。HHVMでも大半の場合は同じ動作になるのですが、浮動小数点数と16進数値文字列の組み合わせに限って16進文字列が0.0として比較されるようです。


<?php
var_dump(1.0 == "0x1"); // HHVM: false, PHP: true
var_dump(0.0 == "0x1"); // HHVM: true, PHP: false

これはHHVMのバグだと思われます。==処理の分岐が複雑すぎて間違えたんでしょうか。


整数の範囲を超えた10進数値文字列浮動小数点数として数値比較される

PHPで数値文字列同士を==で比較するときは原則として数値比較されるのですが、約2年前の修正から数値比較で精度が落ちる場合には文字列比較するようになりました(参考:「PHP 5.4.4から==の挙動が一段と難しくなりました - hnwの日記」)。しかし、HHVMはこの変更に追従していないようです。


これは次のようなコードで確認できます。


<?php
var_dump("9223372036854775807"=="9223372036854775808"); // HHVM: true, PHP: false

HHVMの挙動は少し前のバージョンのPHPと同じですから、実用上はそれほど大きい問題ではないでしょう。しかし、これはPHPの全変更に追従し続けるのは無理という証拠だとも言えそうです。特にPHPの場合はChangeLogにも残らずドキュメント化もされないような細かい変更が珍しくないので、全変更を把握することさえ非現実的かもしれません。


HHVMはPHPのCソースコードをかなり利用している


僕が見つけられた違いは上記の2点だけでした。関連する仕様の複雑さを考えるとありえないくらい同じだという印象です。


HHVMの中の人が頑張ったからこそ再現度が高い側面もあると思いますが、PHPソースコードをうまく取り込んでいるおかげもありそうです。たとえば、HHVMのhphp/runtime/base/zend-strtod.cppを見ると、PHPのZend/zend_strtod.cをベースにしているのが明らかです。ソースコードを流用してしまえば、ドキュメント化されていないような仕様であっても再現できますし、何より楽ができそうで良い手ですね。


まとめ

  • HHVMとPHPの==に違いがあるかどうか調べた
    • 2点の違いを見つけたものの、十分互換性があると言えそう
    • とはいえ、PHPの細かい修正すべてに追従できているわけでもなさそう
  • HHVMはPHPのCソースコードをかなり流用している
    • PHPとの互換性が高い理由かもしれない
トラックバック - http://d.hatena.ne.jp/hnw/20141115
ページビュー
1245492