Edited at

PHPのswitchは止めよう

PHPでswitchの使用止め実際にそのように思わせられるバグに出会ってしまったため、止めようと固く決意しました。(しれっと一部修正しました。)


経緯

PHPで書かれた運用アプリのバグ調査をやりました。

バグは毎日データが消えてしまうというものでした。

バグに関連した処理を追っかけていく中で、原因と思わしきコードを見つけました。


sample.php

<?php

function bugFunction($arg) {
switch ($arg) {
case 'daily':
//deleteData()
default:
//doSomething()
break;
}
}


お分りいただけただろうか。

私は、パッと見て原因がわからなかったため3度見て、実際にデバッグしてやっとわかりました。


原因

$argに0が渡されていました。

本来、渡されることが期待されている値は''または'daily'のようでした。

0が渡されていること自体も問題といえば問題だったのですが、そこは置いといてコードの話しに戻ります。

phpのswitchは、緩い比較で真偽判定を行います。

0 == 'daily'

そして、phpでは上記の判定はtrueが返ります。

もう一度言います。

trueが返ります。

どうしてこうなるかという下記の挙動となるからです。

1. 0と文字列の比較のため、'daily'が数字に型変換され0になります。

2. 0 == 0 でtrueが返ります。

というわけで、緩い比較で駄目なら、厳密比較すればいいじゃないということでif文で書き直しました。

めでたし、めでたし。


余談

今回の不具合は上記で終わりだったのですが、ちょっと待ってほしい。

もう一度、最初のコードがこちら。


sample.php

<?php

function bugFunction($arg) {
switch ($arg) {
case 'daily':
//deleteData()
default:
//doSomething()
break;
}
}


case 'daily'の処理内にbreakないんですけども?

そのままdefaultの処理に入ってるんですけど?

ここでやろうとしている処理から判断する限り、明らかに不具合なんですけども?


結論

実際に不具合のダブル役満を見せられた身としては、switch使うのやめない?という気持ちでした。

意図せぬ不具合を起こさないコードが一番のはずなので...