(0 == "") == true

気が付いたら、この前日記書いてから数ヶ月間もほったらかしだった。コメントも付いてたのに無視か・・・。申し訳ないです。

その間色々あったけど、最近衝撃を受けたのが、PHPの異なる型間の比較について。

あまりに間抜けで初歩的と思われることなので、自戒の意味を込めてここに書いときます。

実は、PHPを使い始めて少し経つけど、0 == ""って事実に全く気付いてなかった。恐ろしい・・・。これまで書いたテストは全部通ってきたから、テストがぬるかったんだな。もしくは、運良く全く影響の無い箇所でのみ使用してたのか。

確かに、マニュアルにも

整数値を文字列と比較する際、文字列が 数値に変換されます。 数値形式の文字列を比較する場合、それは整数として比較されます。これらの ルールは、 switch 文にも適用されます。

とあるし、それも読んだ記憶があったのだけど、全く気付かず。

PHPのような型付けの弱い言語って、色々と楽なんだけど気をつけないと罠に嵌るなあ。つまり、型が存在していない訳ではなく、適宜動的に型付け、変換が行われているのだということを意識しといた方が良い、という事だな。(というか、そうしているつもりだったんだけど。)

上記引用の通り、「文字列が 数値に変換されます」とあるが、その変換に仕方にも注意しとかないといけない。例えば、

("1,000" == 1) === true
("1,000" == 1000) === false
("a50b" == 50) === false
("50b" == 50) === true

ってな感じになる。マニュアルによると、

 数値として文字列が評価された時、結果の値と型は次のように定義されます。

文字列は、'.'、'e'、'E' のどれかが含まれている場合は float、それ以外は整数として評価されます。

文字列の最初の部分により値が決まります。文字列が、 有効な数値データから始まる場合、この値が使用されます。その他の場合、 値は 0 (ゼロ) となります。有効な数値データは符号(オプション)の後に、 1 つ以上の数字 (オプションとして小数点を 1 つ含む)、 オプションとして指数部が続きます。指数部は 'e' または 'E' の後に 1 つ以上の数字が続く形式です。 

ということだ。なるほどね。

型の問題を避けるなら===や!==を使うとか、文字列として比較するならstrcmpを使うとか、文字列に変換した時の文字列長だけチェックしたい時はstrlenとか、適宜使い分けていくべき、ということでした。

他にも似たような落とし穴がありそうで怖い・・・。