どうも、ITエンジニアな隣の鈴木(@next_suzuki)です。
【PHPでハマった・失敗した話】シリーズの第一弾です。
基本構文(foreach・switch)で陥った落とし穴 について語ります。
概要
PHPの基礎構文「foreach」と「switch」を組合せたプログラムを記述したら、バグ・不具合を含んだソースを生み出してしまった。
事象
ループ処理を組み込んだAPIを作成して、フロント側で表示させたら、意図した結果が得られずバグが発生。
原因は何だ?!
問題のコード
下記が問題のプログラム・ソース。
$total = 0;
$numberArray = [1, 2, 3, 4];
foreach($numberArray as $number){
switch($number){
case 3:
continue; // ここでforeachを抜けるはずが、処理が継続された。
default:
break;
}
$total += $number; // $numberが"3"のときも加算されてしまう
}
結論
continue の使い方が謝っていた。
解決方法
PHPのお作法として、switch文で外のループを抜ける際は外ループを指定する必要があるらしい。
よって、外ループを指定するために continue 2 と記述すべきだった。
正常なコード
$total = 0;
$numberArray = [1, 2, 3];
foreach($numberArray as $number){
switch($number){
case 3:
continue 2; // 外側のループ(foreach)に戻ります。
default:
break;
}
$total += $number;
}
振り返り
ハマった・失敗した時に抱いた感情・学び。
情けない
プログラムを書くようになって10年以上が経過した。
もう10年もプログラムを書いているのに、こんな初歩的なミスで失敗するのか…。とショックだった。
PHPの経験が浅いとはいえ、こんなことも知らない自分が情けなかった。
C系の言語と違うのか
僕は元々はC++などのC系が専門なので、この基本構文のことを知らなかった。
C++だとbreakでループを抜けて次のイテレーションへ進む。
PHPはC言語を元に作成されているはずなので、同じ挙動になるか思っていたけど違った…。
continueの数値指定
失敗したおかげで学んだわけだが、PHPはcontinueで数字を指定すれば外ループまで抜けることが可能らしい。
例えば多重ループの時に、内側のループにいる時に、外側のループを数字で指定すれば、外まで処理が抜けてくれる。
$total = 0;
$loopArrayOne = [a, b, c];
$loopArrayTwo = [1, 2, 3];
foreach($loopArrayOne as $number){ // continue 3の場合に戻る位置
foreach($loopArrayTwo as $number){ // continue 2の場合に戻る位置
switch($number){
case 3:
continue 3; // 外側のループ(loopArrayOne)に戻ります。
default:
break;
}
$total += $number;
}
}
まあC++でもgoto文が存在するが、あまり使用するべきではない。
C++で多重ループから抜ける場合、if文でフラグを使用してループから抜けていたが、if文が大量に発生して可読性が落ちて嫌だった。
しかし、PHPだとcontinueが使用できるので、コードが煩雑にならなくて便利だな。とは思った。
(もしかしたらPHPエンジニア界隈ではC++のgoto文みたいにご法度なお作法かもしれないけど…)
match
switch文の代わりに、match式という構文が存在するらしい。
存在を知らなかったので学べてラッキーだった。
おわり
ハマった・失敗した時は、「こんなことも知らないのか」と情けなくて落ち込んだ。
しかし、プログラミングでハマる・失敗なんて、だいたいこんなお作法系なのである。
新しい言語が開発されて学ぶたびに、ぶち当たる問題なのだ。
新しい知識に挑戦している結果なのだから、前向きにとらえて、経験を積み重ねていきたいと思う。