PHPは==で値を比較すると、必要に応じて型の変換が起こります。
型の変換が起こった結果、本当はTRUEとなって欲しいのに、FALSEになったり、本当はFALSEになって欲しいのにTRUEになったりします。
したがって、PHPで値を比較する場合は、==ではなく===、!=ではなく===を使用すべきです。
そんなことを知らない何年も前の私は普通に==や!=を使用しています。
では===や!==に書き直せばいいかというと、単純にそうもいかず暗黙の型変換に頼っている部分があって、ちゃんと考えて書き直していかないとおかしな動きをすることもあり放置しています。
今日は、そんな放置していたスクリプトをで起きた話題です。
最近、エロゲー批評空間の携帯電話Verを作りました。
ご要望板で「
エロゲー批評空間の携帯電話Ver において長文感想のあるコメントに(GiveUP)が表示されている」とのご指摘がありました。
※このように条件を明確にしてバグをご指摘頂けると本当に助かります。自分でバグを引く条件を見つけるのはつらい場合が…そもそも、ちゃんとテストししろということなのですが…
スクリプトを見ると…一見大丈夫でした。
function toukei_kansuu_comment_hitokoto($i,$tokuten,$gid,$gamename,$bid,$brandname,$memo,$oid,$netabare,$hitokoto,$tourokubi,$uid,$giveup='f'){
~省略 ~
if( $giveup == 't' ){
print "<span style=\"font-weight: bold;\"><b>(GiveUp)</b></span>";
}
~省略 ~
}
な感じで、$giveupに「t」が入ったときだけgiveupと表示します。
$giveupには、データベースから取得してきた値が入ります。
データベースから
giveup
に関する値を取得すると、「t」か「f」が入ってきます。
ですので、$giveupには「t」か「f」しか入ってこないはずなのですが、if文の前の$giveupの値を見ると「0」が入っていました…
「t」か「f」しかはいってこないはずの$giveupになぜ0が入ってくるのか?はおいておいて、なぜ0 == 't' がTRUEになるのだろう?と思いました。
を見ますと、==による緩やかな比較の表に"php"と0を比較するとTRUEと書いてありました。
文字列phpを数値に変換すると0になります。
ちなみに、いろんなところに書いてありますが、文字列3abcを数値に変換すると3になります。
さて、そもそも
$giveupになぜ0が入っているのか?を調べました。
toukei_kansuu_comment_hitokoto関数は、データベースからとってきた値を渡して表示用に整形する関数です。
呼び出し側の
toukei_kansuu_comment_hitokotoは$giveupの部分に何を渡しているかと思ったら、0を渡していました…、原因はこれです。
toukei_kansuu_comment_hitokoto($i,$tokuten,$gid,$gamename,$bid,$brandname,$memo,$oid,$netabare,$hitokoto,$tourokubi,$uid,0,$giveup)
のように渡していました。
本当は、toukei_kansuu_comment_hitokotoの$giveupの部分が、function toukei_kansuu_comment_hitokotoの$giveupにいかないといけないと思いました。
スクリプトの変更履歴を追ったところ、もともとのtoukei_kansuu_comment_hitokoto関数は toukei_kansuu_comment_hitokoto($i,$tokuten,$gid,$gamename,$bid,$brandname,$memo,$oid,$netabare,$hitokoto,$tourokubi,$uid,$time_short=0,$giveup='f')でした。
ここで、PHPって、呼び出し側の引数と呼び出される側の引数が違っていてもいいの?と思いました。
OKでした。
<?php
function foo()
{
$numargs = func_num_args();
echo "引数の数: $numargs\n";
}
foo(1, 2, 3);
?>
とやると、3と表示されます。
ちなみに、
function foo( $a )
{
$numargs = func_num_args();
echo "引数の数: $numargs\n";
ecoo $a;
}
foo(1, 2, 3);
?>
とすると、 ecoo $aの部分は当たり前ですが1と表示されます。
そもそも関数の中で、渡ってきた値が妥当かどうか…今回は、$givupの値には、't'か'f'しかこないはずなのに、0が入っていたけど、チェックしていなかった…のも原因です。
妥当性はチェックしましょう…
まとめ
- PHPでの比較は===と!==を使おう
- PHPには可変長引数がある
- 書いてて面倒だなあと思うことがあったり、関数に渡ってくる値の種類が増えたときに関数の修正を忘れて「おかしな値が入っています」と言われることもあるけど、渡ってくる値はちゃんとチェックしよう