switch ($value)は1つの値をcaseラベルの一覧と比較し、最初に一致したラベルの下にあるコードを実行します。各caseはbreakで終わり、どれにも一致しなかったものはすべてdefaultが処理します。
$dayを'fri'、'sun'、'wed'にして、もう一度実行してみてください。defaultが最後のcaseならbreakは不要です。
1つのブロックに複数のcase
複数の値で同じコードを実行するには、間に何も書かずにcaseラベルを並べます。一致したラベルは、その下のコードへと続きます。
matchと違い、switchにはcase 'jpg', 'jpeg':というカンマの構文はありません。ラベルを並べる方法しかありません。
フォールスルー:breakがないとどうなるか
switchを止めるのはbreakです。breakがないと、PHPは一致したcaseを実行したあと、ラベルを無視してその下のすべてのcaseへと進み、breakか終わりにたどり着くまで止まりません。
ここでのフォールスルーは意図的なもので、各プランは自分の機能に加えて、それより安いプランの機能をすべて受け取ります。意図して書くときは、次に読む人が「直して」しまわないよう、// no breakのようなコメントを付けましょう。意図していない場合、breakの書き忘れはswitchでもっともよくあるバグの1つです。
switchはゆるい比較(==)を使う
各caseは===ではなく==で確認されます。数値の文字列は数値に一致し、nullはfalseと""に一致し、trueはtrueと評価されるあらゆる値に一致します。セルをタップして2つの演算子を比べてみてください。
| $a == $b | 0 | 1 | "0" | "1" | "" | null | false | true | "a" | "10" | "1e1" |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | |||||||||||
| 1 | |||||||||||
| "0" | |||||||||||
| "1" | |||||||||||
| "" | |||||||||||
| null | |||||||||||
| false | |||||||||||
| true | |||||||||||
| "a" | |||||||||||
| "10" | |||||||||||
| "1e1" |
実際の影響として、フォームから来た文字列"1"は何も変換しなくてもcase 1:に入ります。これはたいてい望ましい動きです。ただし、空でない文字列でのswitch (true)や、nullとcase false:の組み合わせは、予想外のcaseを選ぶことがあります。
nullの行に注目してください。null == 0がすでにtrueで、case 0:が先にあるので、case false:には届きません。ゆるい比較では、caseの順番で結果が変わります。PHP 8以降は0 == "a"がfalseなので(PHP 7ではtrueでした)、数値でない文字列がcase 0:に一致することはなくなりました。===が必要なら、このページの最後で扱うmatch式を使いましょう。
範囲や条件にはswitch(true)
caseラベルにはどんな式でも書けます。switch (true)にすると各caseが条件になり、最初にtrueと等しくなったものが選ばれます。
各caseが本当のboolになるようにしてください。ゆるい比較のため、case $name:は$nameが空でない文字列なら常に一致してしまいます。
ループの中のswitch:breakとcontinue
ループの中では、switch内のbreakはswitchから抜けるだけで、ループからは抜けません。ループを止めるにはbreak 2を使います。switch内のcontinueはbreakと同じ動きをし、PHPはコンパイル時に警告を出します:"continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"?。ループの次の繰り返しに進むにはcontinue 2と書きます。
switchとmatchの違い
PHP 8で追加されたmatchは、switchのほとんどの用途をより少ないコードでこなします。===で比較し、値を返し、フォールスルーせず、カンマ区切りの条件を書け、何にも一致しないとUnhandledMatchErrorを投げるので、caseの書き忘れが黙って通り抜けることはありません。
caseに複数の文が必要なときや、プランの例のようにフォールスルーそのものが目的のときはswitchを使いましょう。値を結果に対応させるなら、matchのほうが短く安全です。
よくある質問
PHPのswitchで1つのブロックに複数のcaseを使うには?
間にコードを入れずにcaseラベルを並べます:case 'sat': case 'sun': echo 'weekend'; break;。各ラベルは共通のコードへフォールスルーします。switchにはcase 'sat', 'sun':という構文はなく、このカンマの形はmatchのものです。
PHPのswitchは厳密な比較を使いますか?
使いません。switchはゆるい==で比較するので、case '1':は整数の1に一致し、case 0:は'0'に一致します。厳密な===比較には、match式か、各caseの中で===を使うswitch (true)を使います。
PHPのswitchでbreakを忘れるとどうなりますか?
実行がフォールスルーします。一致したcaseのあと、PHPはbreakかreturnかswitchの終わりにたどり着くまで、その下にあるすべてのcaseのコードを実行し続けます。意図した動きのこともありますが、たいていはバグです。
PHPのswitchで「より大きい」のような範囲を判定できますか?
switch (true)を使えばできます。各caseにcase $score >= 90:のような条件を書き、最初にtrueになったものが実行されます。match (true)式も同じことを厳密な比較で行い、値を返します。