hnwの日記

『プログラミングPHP』の間違いを発見した

O'REILLY本の『プログラミングPHP 第2版』をid:cocoitiさんから借りて眺めてみました。何で買わないの?って言われそうですけど、とりあえずPHP公式マニュアルに書いていないことが書いてあるのかな、ってことが確認したかったんです。


というのも、この本の筆者にはPHPの偉い人であるRasmusさんが名を連ねています。中の人公認の本となれば公式なドキュメントに準ずる扱いの情報と思っていいでしょう(思い込みのような気もしますが)。ですから、マニュアルに書いていない情報がこの本に書かれていたとしても、今後のPHPのバージョンでその情報が正しいことを期待できるんじゃないか、と考えたわけです。


PHPの公式マニュアルは非常に充実していると思うんですが、細かい部分の説明は足りないことが多い気がします。僕はマニュアルの==演算子の挙動の説明が不十分なのが気になっていたのですが、この本の43ページにこんな記述を見つけました。

第1オペランド 第2オペランド 比較方式
数値 数値 数値による比較
数値形式の文字列 数値形式の文字列 数値による比較
数値形式の文字列 数値 数値による比較
数値形式でない文字列 数値 辞書順による比較
数値形式の文字列 数値形式でない文字列 辞書順による比較
数値形式でない文字列 数値形式でない文字列 辞書順による比較


これは比較演算子について、両辺の型と内容に応じて比較演算子がどういう挙動になるのかをまとめた表です。これはPHPマニュアルより踏み込んだ記述だと言えます。というのも、PHPマニュアルには下記のように整数の場合しか書かれておらず、浮動小数点数については何も書いていないんです。

整数値を文字列と比較する際、文字列が数値に変換されます。数値形式の文字列を比較する場合、それは整数として比較されます。

PHP: 比較演算子 - Manual


やった!本家マニュアルにも書いていない内容を中の人が記述してるよ!これで浮動小数点数の挙動は今後も安心だ!かと思いきや、実はこれってPHPマニュアルの記述と矛盾してるんですよね。表の4行目によれば「数値形式でない文字列と数値を比較する場合は辞書順で比較する」となっていますが、これはマニュアルの「整数値を文字列と比較する際、文字列が数値に変換されます」と矛盾します。

$ php -r 'var_dump("3zz"<=3);'
bool(true)
$ php -r 'var_dump("3zz"<="3");'
bool(false)


上記の通り、挙動を確認してみても前者は数値として比較しており、PHPマニュアルの方が正しいんですよね。そんなわけで、『プログラミングPHP 第2版』の表の4行目はキーボードが滑っただけで、正しくは「数値による比較」なんですよ。きっとそうに違いありません。


そんなわけで、比較演算子の正しい挙動は下記の通りだと思います。これが本当に中の人の認識だとすれば、本家マニュアルにも書いて欲しい内容ですね。

第1オペランド 第2オペランド 比較方式
数値 数値 数値による比較
数値形式の文字列 数値形式の文字列 数値による比較
数値形式の文字列 数値 数値による比較
数値形式でない文字列 数値 数値による比較
数値形式の文字列 数値形式でない文字列 辞書順による比較
数値形式でない文字列 数値形式でない文字列 辞書順による比較


翻訳者のid:takagimasahiroさん、DISっているようで申し訳ありません。中の人がPHPマニュアル以上のことを書いた本ならPHPプログラマ全員必要ですよね!さっそく会社で買います!そして本を貸して頂いたid:cocoitiさん、ありがとうございました。おかげさまで記事が増えました。