ちょっと、下のPHPのサンプルコードを見て欲しい。
<?php
for( $y = 1971 ; $y <= 1986 ; $y += 1 ){
$dtBirth = new DateTime("1970-05-05");
$dtToday = new DateTime("$y-01-01");
$inter = $dtToday->diff($dtBirth);
$num = $inter->y;
printf("\$num=%2d intval(\$num/5)=%d\n", $num, intval($num/5));
printf("\$num=%2d intval(\$num/5)=%d\n", $num, intval($num/5));
print "\n";
}
1970年5月5日誕生日の人が、1971年から1986年までの1月1日に何歳になっているかという計算をして、さらにその年齢を、ある計算をするために5で割った商を整数化しています。そして同じ行を2度出力しています。
コードを見る限り、2度同じ行が表示されるはずです。
実行した結果を見ると、たしかに0歳から6歳までは正常に動いています。ところが、7歳になった途端、1行目の結果がおかしくなっています。(割り切れるときは正しい動作をします)
$num= 0 intval($num/5)=0
$num= 0 intval($num/5)=0
$num= 1 intval($num/5)=0
$num= 1 intval($num/5)=0
$num= 2 intval($num/5)=0
$num= 2 intval($num/5)=0
$num= 3 intval($num/5)=0
$num= 3 intval($num/5)=0
$num= 4 intval($num/5)=0
$num= 4 intval($num/5)=0
$num= 5 intval($num/5)=1
$num= 5 intval($num/5)=1
$num= 6 intval($num/5)=1
$num= 6 intval($num/5)=1
$num= 7 intval($num/5)=0
$num= 7 intval($num/5)=1
$num= 8 intval($num/5)=0
$num= 8 intval($num/5)=1
$num= 9 intval($num/5)=0
$num= 9 intval($num/5)=1
$num=10 intval($num/5)=2
$num=10 intval($num/5)=2
$num=11 intval($num/5)=0
$num=11 intval($num/5)=2
$num=12 intval($num/5)=0
$num=12 intval($num/5)=2
$num=13 intval($num/5)=0
$num=13 intval($num/5)=2
$num=14 intval($num/5)=0
$num=14 intval($num/5)=2
$num=15 intval($num/5)=3
$num=15 intval($num/5)=3
どうも調べるとDateIntervalのバグらしい(intvalのバグならもう、びっくりですよねえ(w))。 このバグの不可思議なところは、DateTimeクラスのdiff関数の返すDateInterval型そのものではなく、代入している$num変数で不可思議な事象が発生していること、そして、同じ計算を2回行うと正常になるところです。
因みに、この現象は全てのPHPで起きる訳ではありません。
Windows用PHPのver5.3系のさらにvc6系と呼ばれる処理系だけに発生しているようです。
このバージョンのPHPのDateIntervalには、不具合があるので使わないようにというテークノートが出ています。(尤もバグを発見してから見つけましたが)
<?php
ini_set("date.timezone", "Asia/Tokyo");
$a = DateTime::createFromFormat("Y-m-d", "2010-01-01");
$b = DateTime::createFromFormat("Y-m-d", "2010-01-03");
$d1 = $b->diff($a);
printf( "d1->days=%d\n", $d1->days);
$d2 = $a->diff($b);
printf( "d2->days=%d\n", $d2->days);
こちらは判りやすく常に同じ値を返すようです。(^_^;)
d1->days=6015
d2->days=6015
不具合はどんな言語でも多少はつき物です。
流石にまったく関係のない関数を通すと不正が起きる(しかも再現可能)なんていうバグは、30年以上プログラミングに関わっているけど、初めてですね。ということで、このバグを「わが生涯で最もミステリアスなバグ」に認定いたします(笑)。
ただ、PHPに関しては、内部構造の筋の悪さ(https://bitstar.jp/blog/?p=756)が、裏に潜んでいるんじゃないかなあと思ってしまいます。
PS.
Love & Hate Languageというのが昔のMatzの日記にあったので、ちょっと試してみた。(w)
“I love xxxxxx”や”I hate xxxxxx”を検索してその検索結果数を比較するというゲーム。Rubyは、Matzが試した7年前くらいには100倍を維持していましたが、現在では10倍くらい。これでも、他の言語よりすごいですね。(実際にはProgramming “I love XXXX”のように、Programmingに関係していないページを除くようにしてあります。)
ダントツは、言語ではないけど、jQueryでした。
ちなみにワーストは、java。
Laguange | Love | Hate | Rate |
---|---|---|---|
Ruby | 223,000 | 22,200 | 10.05 |
Perl | 223,000 | 22,200 | 4.45 |
PHP | 202,000 | 69,300 | 2.91 |
C++ | 72,500 | 51,000 | 1.42 |
java | 192,000 | 147,000 | 1.31 |
jQuery(*1) | 58,900 | 3,820 | 15.42 |
*1 javascriptのライブラリ jquery.com
yna