PHP 入門

PHP switch 文

switch 文は、単一のバリアブル(変数)またはエクスプレッション(式)を、一連の候補値と比較するために特化した制御構造です。

一つの変数が複数の異なる具体的な選択肢と一致するかどうかをチェックする必要がある場合、冗長になりがちな if...elseif 文のチェーンに代わる、より簡潔でリーダビリティ(可読性)の高い選択肢となります。

1. 構造と実行フロー

switch 文は一つの式から始まります。PHP はこの式を一度だけ評価し、その結果を各 case の値と順番に比較します。マッチする項が見つかると、その case 内部のコードブロックが実行されます。

ここで極めて重要なポイントは、一度マッチすると、PHP は switch ブロック内の後続のコードをすべて実行し続けるという点です。たとえそれらが他の case に属するコードであっても、明示的に停止を指示しない限り実行されます。この現象は「フォールスルー(fall-through)」と呼ばれ、break キーワードを使用してこれを制御・阻止します。

<?php
$userRole = 'editor';

switch ($userRole) {
    case 'admin':
        echo "システムへのフルアクセス権限が付与されました。";
        break; // ここで実行を停止し、switch を抜ける
    case 'editor':
        echo "コンテンツ管理権限が付与されました。";
        break; // ここで実行を停止し、switch を抜ける
    case 'subscriber':
        echo "読み取り専用権限が付与されました。";
        break;
    default:
        echo "アクセスレベルが割り当てられていません。";
}
?>

この例では、$userRole 変数の値が 'editor' であるため、スクリプトは「コンテンツ管理権限が付与されました。」を出力して switch を抜けます。もし break がなければ、そのまま下の処理へ進んでしまい、「読み取り専用権限が付与されました。」だけでなく、default 内のメッセージまで出力されてしまう可能性があります。

2. デフォルトブランチ (default)

default ブランチはオプショナル(任意)ですが、記述することを強く推奨します。これは「フォールバック」としての役割を果たし、前のすべての case がマッチしなかった場合にのみ実行されます。機能的には、if...elseif...else 構造における最後の else と同等です。

標準的な switch の実行ロジックは以下のように理解できます。

  1. Switch 開始: 式の値を評価する。
  2. 式の一致確認: Case 1、Case 2... と順番に比較する。
  3. コード実行: マッチした場合、対応するコードブロック(Block 1 や Block 2 など)を実行する。
  4. マッチなし: 上記の条件を一つも満たさない場合、default コードブロックを実行する。
  5. 脱出/終了: break に遭遇した後、直接外へ飛び出し、スクリプトの後続コードの実行を継続する。

3. ゆるい比較とタイプセーフ

PHP の switch 文は「ゆるい比較」(つまり == 演算子)を使用します。これは、switch に渡した値がインテジャー(整数)の 1 であっても、ある case で定義されているのがストリング(文字列)の "1" であれば、マッチしたとみなされることを意味します。

<?php
$id = 1;

switch ($id) {
    case "1":
        echo "このコードはマッチします。暗黙の型変換(Type Juggling)が発生するためです。";
        break;
}
?>

PHP は比較の際にこのような「暗黙の型変換(Type Juggling)」を行うため、タイプの曖昧さが残る変数を扱う場合は細心の注意を払う必要があります。もし厳格な型比較(つまり ===)が必要な場合は、標準の PHP 構文における switch は厳格な一致をサポートしていないため、if...elseif 構造を使用する必要があります。

4. 意図的なケース・フォールスルーの活用

予期しないフォールスルーはバグの温床になりますが、意図的に利用すれば非常に強力なツールになります。同じ結果をトリガーしたい複数の case ブランチをグループ化するために活用できます。

<?php
$month = 'February'; // 2月

switch ($month) {
    case 'December':
    case 'January':
    case 'February':
        echo "現在は冬季です。";
        break;
    case 'March':
    case 'April':
    case 'May':
        echo "現在は春季です。";
        break;
    default:
        echo "現在は夏季または秋季です。";
}
?>

この例では、最初の 2 つの case の後にあえて break を記述していません。これにより、実行フローは直接 'February' のコードブロックまで「フォールスルー」します。これにより、冬の 3 ヶ月間を単一のロジックユニットとしてスマートに処理でき、コードの重複を大幅に削減できています。