PHP switch 條件判斷

switch 用於根據一個變數的不同值執行不同的程式碼。當有多個條件需要檢查同一個變數時,switch 比多個 if...else if 更簡潔易讀。

基本語法

<?php
$day = 3;

switch ($day) {
    case 1:
        echo "星期一";
        break;
    case 2:
        echo "星期二";
        break;
    case 3:
        echo "星期三";
        break;
    case 4:
        echo "星期四";
        break;
    case 5:
        echo "星期五";
        break;
    case 6:
        echo "星期六";
        break;
    case 7:
        echo "星期日";
        break;
    default:
        echo "無效的日期";
}
// 輸出:星期三
?>

break 語句

break 用於跳出 switch 區塊。如果沒有 break,程式會繼續執行下一個 case(稱為 fall-through):

<?php
$grade = "B";

switch ($grade) {
    case "A":
        echo "優秀";
        break;
    case "B":
        echo "良好";
        // 忘記 break,會繼續執行下一個 case
    case "C":
        echo "及格";
        break;
    default:
        echo "不及格";
}
// 輸出:良好及格
?>
忘記加 break 是常見的錯誤,會導致意外的 fall-through 行為。

default 語句

default 處理所有不符合 case 的情況,類似 if...else 中的 else

<?php
$fruit = "grape";

switch ($fruit) {
    case "apple":
        echo "這是蘋果";
        break;
    case "banana":
        echo "這是香蕉";
        break;
    default:
        echo "這是其他水果";
}
// 輸出:這是其他水果
?>

default 可以放在任何位置,但通常放在最後:

<?php
switch ($value) {
    default:
        echo "預設值";
        break;
    case 1:
        echo "一";
        break;
    case 2:
        echo "二";
        break;
}
?>

多個 case 共用程式碼

利用 fall-through 特性,多個 case 可以共用同一段程式碼:

<?php
$month = 2;

switch ($month) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        echo "這個月有 31 天";
        break;
    case 4:
    case 6:
    case 9:
    case 11:
        echo "這個月有 30 天";
        break;
    case 2:
        echo "這個月有 28 或 29 天";
        break;
    default:
        echo "無效的月份";
}
// 輸出:這個月有 28 或 29 天
?>

字串比較

switch 可以用於字串比較:

<?php
$command = "start";

switch ($command) {
    case "start":
        echo "啟動系統";
        break;
    case "stop":
        echo "停止系統";
        break;
    case "restart":
        echo "重啟系統";
        break;
    case "status":
        echo "顯示狀態";
        break;
    default:
        echo "未知指令";
}
?>

switch 的比較方式

switch 使用鬆散比較(==),而非嚴格比較(===):

<?php
$value = "0";

switch ($value) {
    case 0:
        echo "數字零";
        break;
    case "0":
        echo "字串零";
        break;
}
// 輸出:數字零(因為 "0" == 0 是 true)
?>
switch 使用鬆散比較,可能導致意外的結果。如果需要嚴格比較,使用 if...else 或 PHP 8 的 match 表達式。

替代語法

在 HTML 模板中使用替代語法:

<?php $userRole = "admin"; ?>

<?php switch ($userRole): ?>
    <?php case "admin": ?>
        <p>您是管理員</p>
        <?php break; ?>
    <?php case "editor": ?>
        <p>您是編輯者</p>
        <?php break; ?>
    <?php default: ?>
        <p>您是一般使用者</p>
<?php endswitch; ?>

match 表達式 (PHP 8+)

PHP 8 引入了 match 表達式,是 switch 的改進版:

<?php
$grade = "B";

$result = match ($grade) {
    "A" => "優秀",
    "B" => "良好",
    "C" => "及格",
    "D" => "尚可",
    default => "不及格",
};

echo $result;  // 良好
?>

match 的特點

1. 使用嚴格比較 (===)

<?php
$value = "0";

$result = match ($value) {
    0 => "數字零",
    "0" => "字串零",
};

echo $result;  // 字串零(嚴格比較)
?>

2. 是表達式,有回傳值

<?php
$day = 3;

// match 可以直接回傳值
$dayName = match ($day) {
    1 => "星期一",
    2 => "星期二",
    3 => "星期三",
    4 => "星期四",
    5 => "星期五",
    6 => "星期六",
    7 => "星期日",
    default => "無效",
};

echo $dayName;  // 星期三
?>

3. 不需要 break

match 不會 fall-through,不需要 break

4. 必須涵蓋所有情況

如果沒有 default 且沒有匹配的值,會拋出 UnhandledMatchError

<?php
$value = 5;

// 如果沒有匹配的值且沒有 default,會報錯
$result = match ($value) {
    1 => "一",
    2 => "二",
    // UnhandledMatchError: Unhandled match case 5
};
?>

5. 多個值共用

<?php
$month = 2;

$days = match ($month) {
    1, 3, 5, 7, 8, 10, 12 => 31,
    4, 6, 9, 11 => 30,
    2 => 28,
    default => throw new InvalidArgumentException("無效的月份"),
};

echo $days;  // 28
?>

6. 可以使用表達式作為條件

<?php
$age = 25;

$category = match (true) {
    $age < 13 => "兒童",
    $age < 20 => "青少年",
    $age < 60 => "成年",
    default => "老年",
};

echo $category;  // 成年
?>

switch vs match

特性switchmatch
比較方式鬆散 (==)嚴格 (===)
回傳值
break需要不需要
fall-through
未匹配處理跳過或執行 default拋出錯誤
PHP 版本全部8.0+

實際應用範例

HTTP 狀態碼處理

<?php
$statusCode = 404;

// 使用 switch
switch ($statusCode) {
    case 200:
        $message = "OK";
        break;
    case 301:
    case 302:
        $message = "重新導向";
        break;
    case 400:
        $message = "錯誤的請求";
        break;
    case 401:
        $message = "未授權";
        break;
    case 403:
        $message = "禁止存取";
        break;
    case 404:
        $message = "找不到頁面";
        break;
    case 500:
        $message = "伺服器錯誤";
        break;
    default:
        $message = "未知狀態";
}

// 使用 match (PHP 8+)
$message = match ($statusCode) {
    200 => "OK",
    301, 302 => "重新導向",
    400 => "錯誤的請求",
    401 => "未授權",
    403 => "禁止存取",
    404 => "找不到頁面",
    500 => "伺服器錯誤",
    default => "未知狀態",
};

echo $message;  // 找不到頁面
?>

路由處理

<?php
$action = $_GET['action'] ?? 'index';

switch ($action) {
    case 'index':
        include 'views/home.php';
        break;
    case 'about':
        include 'views/about.php';
        break;
    case 'contact':
        include 'views/contact.php';
        break;
    case 'login':
        include 'views/login.php';
        break;
    default:
        http_response_code(404);
        include 'views/404.php';
}
?>

計算器

<?php
function calculate($a, $operator, $b) {
    return match ($operator) {
        '+' => $a + $b,
        '-' => $a - $b,
        '*' => $a * $b,
        '/' => $b !== 0 ? $a / $b : throw new DivisionByZeroError(),
        '%' => $a % $b,
        '**' => $a ** $b,
        default => throw new InvalidArgumentException("未知的運算子:$operator"),
    };
}

echo calculate(10, '+', 5);   // 15
echo calculate(10, '*', 3);   // 30
echo calculate(2, '**', 10);  // 1024
?>