[0] PHP比較演算時の型変換の罠。-[Id of Radiance ver.5]





■ PHP比較演算時の型変換の罠。

 PHPには「比較演算子」と言うものがあります。…いやわざわざ改めて言う事じゃないですけどさ(苦笑)。
よーするに「==」「>」「<」の事です。

 この比較演算子を使って分岐処理、ってのは一般的によく行われてる処理なワケですが、PHPで比較演算を行う場合に、比較対象の変数が「文字列」なんだけどその中身が「整数」として解釈出来る場合、自動的に整数と判断して比較を行います。
例えば
$a = "001";
$b = 1;
if($a == $b) {~}
 と言った処理があった場合、文字列$aの「"001"」は整数「1」と解釈されて、if文がTRUEと判断されます。桁指定の文字列で数字を表してるような変数があって、それを実際の整数と比較する際に、整数変換やゼロサプレスが不要という利点があります。
 まあ現実的にはこの利点を積極的に利用する、と言うことはあんまりなく、たまたま文字列の数字型だったんだけどそのまま数字と比較することもできたから楽だったな、と言った後付けの便利さではあります。というか、普通は比較する対象の変数の型は作成者が明確に意識してるハズなんで、あんまり意味はないけど、別に悪さをするものでもないのでそのままにしてる、と言った方がいいかもしれません。僕的に、ですが。

 ところがコレがちょっと微妙な罠を作りだしまして(苦笑)。

 とあるシステムで、登録内容を管理するのに16進数桁の文字列で内部IDを管理してたシステムがありまして、つまるところ000〜FFFのよーな範囲で処理しておりました。ホントの16進ではなく文字列にしたのはその方が柔軟にコントロールできるからでした。
 で、その内部IDが一致してるかとかの判断をフツーに
if($id_1 == $id_2) {〜}
みたいにやってて、途中までは全然問題なく動いてたワケですが、ある特定の2つのIDで、どー見ても中身が一致してないのに同一のモノであると判断する現象が発生。

 まず両者の中身が別物なのは確か。参照で同じ所を見てるとゆーネタも無し。また、発生する2つのIDに限らず近い値の場合でも発生する。しかしある程度値が進むとまた別の値と判断するようになる。
 明らかに異なる文字列を、なんらかの理由で同じ値と判断してる、としか思えない。ここで頭に浮かんだのは上記の型変換。しかし症状が発生してる文字列を見てみるとアルファベットが記述してあるので数字とは判断されない、ハズ。
 同じ値と判断してるのは「0E1」と「0E2」と言った、真ん中に「E」を挟んで両端が数字になってる文字列…。

 「E」…?

 つまりアレです。数字を挟んで間に「E」がある文字列の場合、指数表現されてる整数として判断してたワケです。 0E1の場合0x101=0、0E2の場合0x102=0…つまりどっちも0として比較してたため比較がTRUEになっていた、と。中途半端に16進型をテキスト表記したのが祟ったか(苦笑)。
 ちなみに対処法は簡単で、変数比較を「==」でやってたところを「型の一致」まで確認する「===」に変えるだけ。

 まあ、よっぽどの事が無いと遭遇しない変なパターンではありますが、これにかぎらず PHPの「==」はごく希に想定外の動きをすることがあるので、使う変数の内容が明確ならば「===」を使っていた方が安全なのかもしれません。

関連タグ:PHP
2007-05-18 [技術・作業]

関連記事: