PHPにおける数値と文字列のヘンな比較結果2007年12月16日 04時09分25秒

0 == 'str' // true

PHPSPOTでこんなエントリがあった。

タイトルだけみたときは「0 == '0'のことか?そりゃ当然じゃん」とか思って記事を見たところ、
$a = 0;
$b = 'str';

if( $a == $b ) {
	echo 'equal';
} else {
	echo 'not equal';
}
なんてコードが掲載されてた。試してみると確かに「equal」と出力される。どういうこっちゃ?

仕様を調べてみる

ちょっとこの現象は、どういう理屈に基づいてこうなるのかさっぱりわからないので、仕様上どうなっているのか調べてみた。

違う型同士を比較するので、暗黙の型変換が発生するだろうと思い、マニュアルの「型の相互変換」を見てみたがそれっぽいことは記述されていなかった。

このページの最後に参照リソースとして「PHP 型の比較表」があったのでそちらを見てみると、 「==による緩やかな比較」という表には確かに数値の「0」と文字列「php」の比較結果は「TRUE」になると記載されているので、今回の現象はどうやら仕様らしいことはわかった。が、納得いかん

で、他に関連しそうなところがないかと思って目次を探してたら、「比較演算子」の項があったので見てみると、

整数値を文字列と比較する際、文字列が 数値に変換されます。
とある。ってことは、文字列'str'が暗黙的に整数に変換されたものと整数0が比較されたということのようだ。

文字列 → 数値変換ってどうなっとるの?

これで足がかりが見つかったので、もう一度「型の相互変換」から追っかけてみたところ、「文字列」の「文字列変換」の節

文字列の最初の部分により値が決まります。文字列が、 有効な数値データから始まる場合、この値が使用されます。その他の場合、 値は 0 (ゼロ) となります。
とあった。

検証してみる

なるほど、上記仕様なら、文字列'str'は数値0と見なされるので、最初のコードで「等しい」と判断されるわけだ。ではそのとおりに振舞うか、テストしてみよう。

文字列の先頭に数字を入れればその数字が示す数値に変換されるはずだし、比較する数値を0以外にしても等値にならないはずなので、最初のコードを含めて3通り試してみた。

C:\Documents and Settings\dara-j>php -r "echo 0 == 'abc' ? 'equal' : 'not equal';"
equal
C:\Documents and Settings\dara-j>php -r "echo 0 == '1abc' ? 'equal' : 'not equal';"
not equal
C:\Documents and Settings\dara-j>php -r "echo 1 == 'abc' ? 'equal' : 'not equal';"
not equal
C:\Documents and Settings\dara-j>
おお、予想通り。やっと納得がいった。

結論

比較だけなのに勝手に文字列→数値変換が発生するので気をつけようってことね。しかしこれ、仕様としてはあまり行儀が良くない気がするなぁ...