PHP の言語仕様は、ランタイムのコンパイル環境に依存します。

個人的には、PHP って、嫌いな言語じゃないんだけど、とかく宗教戦争に持ち込まれやすい。攻撃する側は、「言語としてなっとらん」みたいな主張が多くて、具体的にどこが? と思っていたんだけど、これほど面白い例は無い。

PHPの比較の素晴らしさ加減は正常

「16 進数の表記は整数に変換するけど、じゃぁ、8進数は」という辺りが傑作なのだが、この挙動、結構、奥が深かった。

PHPでは"0x0A"=="10"がtrue | 水無月ばけらのえび日記

上記ページを読むと、整数に変換するかどうかは、C のライブラリ関数である strtod に依存しているらしい。で、このページのコメントに書かれているように、その strtod 自体が、コンパイラがどの規格に準拠してコンパイルしたかによって、挙動が変わってしまう。C99 準拠してコンパイルすれば、16 進数の表記は整数に変換されるが、そうでなければ変換されない。

となると、元の「"0x0A"=="10"」が true か false かは、

PHP 自体をどうビルドしたか

によって、答えが変わってしまうことになる。つまり、言語としては、

「"0x0A"=="10"」の結果は不定

ということになる。

PHP 支持派の人は、「=== を使うべき」と言っているが、それは文字列として比較したい、という明確な意図を持って比較する場合の回避策であり、「"0x0A"=="10"」が true となる事を期待したコード書いている場合、つまり、

  • 変数に文字列を格納し、
  • 数値の文字列表現として 16 進数を許容し、
  • 数値として比較する。

という場合、期待した動作になるかどうかは、実行環境に依存することになる。おそらく「"0x0A"=="10"」は、大部分の Linux では true となる事が期待できるが、商用 UNIX だと false になる可能性が高い*1Linux だって、コンパイルオプションで「あえて、準拠する規格を下げて」コンパイルしたら、false になる。PHP 本体のバージョンでもなく、動作 OS でもなく、「コンパイルした時、どうだったか」で挙動が変わる、というのは、さすがに酷い。

これを見たら、「PHP がハッシュと配列を区別していないのは気持ち悪い」なんてのはどうでもいい。それは、言語としての思想なんだから、それで PHP を批判するのは宗教戦争にしかならない。でも、この比較の件は、実行環境によって全く反対の答えになってしまう、というのだから、たちが悪い。

極端なことを言えば、PHP をちゃんと勉強したかったら、C 言語の規格にも詳しくなきゃ、正しいコードは書けない、というのだから...。

PHP のお手軽さ、というのは自分も知っているので、これで PHP を全部否定するようなことは、個人的には全く思わないが、日頃言われている「『PHP はいい加減』という事が事実」いうことは、これで分かった。

*1:たまたま、この日記のはてブを見たら、どこの商用 UNIX だ、というのがあったが、HP-UX の純正コンパイラで C99 仕様にするためには、コンパイルオプションで指定する必要がある(http://docs.hp.com/ja/5991-4870/ch01s07.html#bgbgacda)。今時の Linux に付いてくる gcc ならデフォルトで C99 としてコンパイルするので、Linux 上で round() を使っていて そのコードを HP-UX 上へ持っていくとビルドに失敗、というのが最近あった(round() 関数は C99 で追加されたもの)。もちろん、コンパイル時に -AC99 を指定するか、gcc を持ってくれば良いのだが、意識していないと C89 でコンパイルされることになる。