phpでは初心者のためにいくつか罠が実装されている。
以下のサンプルコードを見てほしい。実行すると何が表示されるだろうか?
<?php // 二進数文字列を英単語に $binaryToStr = [ "000" => "zero", "001" => "one", "010" => "two", "011" => "three", "100" => "four", "101" => "five", "110" => "six", "111" => "seven", ]; // 素数には" (prime number)"をつける $primeNumberBinaryList = ["010","011","101","111"]; foreach ($binaryToStr as $binary => $str) { if ( in_array($binary, $primeNumberBinaryList, true) ) { $binaryToStr[$binary] = $str . " (prime number)"; } } // 表示する foreach ($binaryToStr as $binary => $str) { print("${binary} => ${str}\n"); }
以下のように表示される事が期待動作だが、実際にはそうはならない。
000 => zero 001 => one 010 => two (prime number) 011 => three (prime number) 100 => four 101 => five (prime number) 110 => six 111 => seven (prime number)
実行してみると以下のように表示される。
なぜか、fiveとsevenが素数と判定されない。
000 => zero 001 => one 010 => two (prime number) 011 => three (prime number) 100 => four 101 => five 110 => six 111 => seven
var_dump($binaryToStr);
してみると、すぐに原因が分かる。
array(8) { ["000"]=> string(4) "zero" ["001"]=> string(3) "one" ["010"]=> string(18) "two (prime number)" ["011"]=> string(20) "three (prime number)" [100]=> string(4) "four" [101]=> string(4) "five" [110]=> string(3) "six" [111]=> string(5) "seven" }
000~011はキーが文字列型になっているが、101~111は数値型になっている。
そのため、サンプルのように文字列型と厳密な比較を行うと偽と判定され、素数と判定されなくなる。
なぜ、101~111のキーが数値型になるかというと、「10進数解釈できる文字列のキーは数値型に変換される」という 誰が得するのか理解に苦しむ 親切な言語仕様になっているからだ。
この仕様を回避する方法はない。(ご存じの方はコメント下さい)諦めて曖昧な比較を使って回避しよう。