National Taiwan University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

台灣大學 AQI 67 24°C PM2.5 11
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 05

控制結構

if、elseif、else、switch 與 match,以及 PHP 怎麼判斷真假
Interaction實作 25 minute(s)

Learning Objectives

  • 用 if、elseif、else 依條件選擇要執行的程式,並說明「由上往下、第一個成立就離開」的規則
  • 說出哪些值當成條件時是 false(0、0.0、""、"0"、空陣列、null),並注意 "0.0" 與 [0] 是 true
  • 用提早 return 取代多層巢狀 if,讓程式比較好讀
  • 在 HTML 裡用替代語法 if: … endif; 控制要輸出哪一段
  • 使用 switch(寬鬆比較、break、多個 case 共用、default)與 match(嚴格比較、有回傳值),並說明兩者的差別

讓程式依情況做不同的事

到目前為止,程式都是從第一行執行到最後一行。真正的程式常常要「看情況」: 分數 90 以上給 A、購物滿千免運、登入的人看到自己的名字、沒登入的人看到登入按鈕。 控制結構(control structure)讓你寫出這種「如果…就…否則…」的邏輯:

if ($score >= 60) {
    echo '及格';
} else {
    echo '不及格';
}

本課介紹 PHP 的三種選擇方式:

寫法 適合
if/elseif/else 任何條件,最常用
switch 一個值和好幾個固定的值比對(舊寫法,很多既有程式在用)
match 和 switch 一樣用途,但比較嚴格、可以直接得到一個值(PHP 8.0 起)

逐步執行動畫裡,注意黃色箭頭跳過了哪幾行:條件不成立的區塊不會執行,箭頭會直接跳過去。

if、elseif、else 與巢狀 if

$score 是 78。PHP 從第 4 行開始由上往下一個一個檢查條件,找到第一個成立的條件(第 8 行的 >= 70),執行它的區塊後就離開整個 if,後面的 else 不會再看。第 18 行開始是巢狀 if:外層條件成立,才會進去檢查內層。

條件的順序很重要;elseif 和 else if

elseif 鏈只會執行第一個成立的區塊,所以範圍大的條件要放後面。下面的寫法永遠不會得到 B:

if ($score >= 60) {          // 85 分在這裡就成立了
    $grade = 'D';
} elseif ($score >= 80) {    // 永遠輪不到
    $grade = 'B';
}

elseif 也可以分開寫成 else if,用大括號時兩者效果相同(else if 其實是「else 後面接一個新的 if」)。 唯一的差別在後面會介紹的替代語法:用冒號 elseif: 的時候不能寫成 else if:。本課一律寫 elseif。

區塊只有一行時可以省略大括號(if ($x > 0) echo '正數';),但之後加第二行時很容易出錯,建議一律寫大括號。

哪些值會被當成 false

if 的條件不一定要是 true/false,任何值都可以放進去,PHP 會先把它轉成布林值。 下面這些值會被當成 false,其他所有值都是 true:

型別 當成 false 的值
布林 false
整數 0
浮點數 0.0、-0.0
字串 空字串 "" 和 "0"
陣列 空陣列 []
null null(包括沒有設定過的變數)

容易猜錯的是字串:只有 "" 和 "0" 是 false,"0.0"、" "(一個空白)、"false" 都是 true; 陣列也一樣,[0] 有一個元素,所以是 true。

這會造成一個常見的錯誤:使用者在表單裡輸入 0,if ($input) 卻把它當成「沒有輸入」。 要判斷「是不是空字串」時,直接寫 $input !== ''(第 04 課的嚴格比較),不要依賴真假值的轉換。

想一想:條件與真假值

1.

下面的程式會印出什麼?

<?php
$a = "0.0";
$b = "0";
$c = [0];
$d = 0.0;
echo $a ? 'T' : 'F', $b ? 'T' : 'F', $c ? 'T' : 'F', $d ? 'T' : 'F';
2.

下面的程式會印出什麼?

<?php
$x = 85;
if ($x >= 60) {
    echo 'D';
} elseif ($x >= 80) {
    echo 'B';
} else {
    echo 'F';
}
第 1 次作答

巢狀太深時:提早 return

條件一多,if 很容易一層包一層,讀的人要一直記住「現在在哪一層」。 寫成函式(function)的時候,可以先把特殊情況處理掉、直接 return,剩下的程式就不用再包在 else 裡。 這種寫法叫提早 return(early return),也有人叫「守衛子句」(guard clause)。

下面的範例用到函式:function 名稱(參數) { … } 定義一段可以重複呼叫的程式,return 把結果交回呼叫的地方,同時結束函式。 函式的完整寫法在第 07 課介紹,這裡先看兩種寫法的差別。

同一個運費規則,兩種寫法

運費規則:金額不合理回傳 -1;會員免運;滿 1000 元免運;其他收 60 元。feeNested 用巢狀 if,feeEarly 每遇到一種情況就直接 return。看動畫時注意:return 一執行,函式就結束,後面的程式不會再跑。

替代語法:和 HTML 混寫

PHP 常常夾在 HTML 裡,決定某一段 HTML 要不要輸出。用大括號的話,<?php } ?> 很難看出是在結束哪個區塊。 PHP 提供另一種寫法:左大括號換成冒號,右大括號換成 endif;:

<?php if ($isLoggedIn): ?>
  <p>歡迎回來</p>
<?php elseif ($isGuest): ?>
  <p>訪客你好</p>
<?php else: ?>
  <a href="login.php">登入</a>
<?php endif; ?>

<?= $name ?> 是 <?php echo $name; ?> 的簡寫。?> 和 <?php 之間的 HTML 會原封不動送出, 條件不成立時,整段 HTML 都不會出現在輸出裡。迴圈也有同樣的寫法(foreach: … endforeach;),第 06 課介紹。

用條件決定輸出哪一段 HTML

看輸出區:已登入時只出現歡迎訊息,else: 之後的「登入」連結不會輸出。?> 後面緊接的一個換行會被 PHP 吃掉,所以 <?php … ?> 自己那一行不會在輸出裡留下空行。

switch:一個值和好幾個值比對

當你要拿同一個值和好幾個固定的值比對時,可以用 switch:

switch ($day) {
    case 'sat':
    case 'sun':                // 多個 case 共用同一段程式
        $type = '週末';
        break;                 // 跳出 switch
    case 'mon':
        $type = '星期一';
        break;
    default:                   // 前面都不相符時
        $type = '平日';
}

使用 switch 要注意三件事:

  1. 找到相符的 case 之後會一路往下執行,直到遇到 break 或 switch 結束,不管下面的 case 是什麼。這叫 fall-through。 刻意利用時(例如上面的 sat、sun 共用),最好加一行註解說明;忘了寫 break 是最常見的錯誤。
  2. switch 用寬鬆比較 ==:字串 '1' 和整數 1 會被當成相符。
  3. default 可以省略;省略時沒有相符的 case,switch 就什麼都不做。

fall-through、寬鬆比較與 switch (true)

$day 是 'fri'。第 9 行的 case 相符後,因為沒有 break,箭頭會繼續走到 mon、tue 的內容。最後一段是 switch (true):拿 true 和每個 case 的條件比對,第一個成立的條件就是相符的 case,常用來判斷範圍。

match:比較嚴格、而且有回傳值

PHP 8.0 加入 match。它和 switch 的用途一樣,但整個 match (…) { … } 是一個運算式(expression), 會算出一個值,可以直接指派給變數或 echo:

$message = match ($status) {
    200, 201 => '成功',        // 多個值用逗號分開
    404 => '找不到頁面',
    default => '其他狀態',
};                             // 注意結尾有分號
switch match
比較方式 寬鬆 ==('1' 和 1 相符) 嚴格 ===(型別也要相同)
結果 敘述,不會產生值,要在 case 裡自己指派 運算式,直接得到一個值
多個值共用 連續寫多個 case 同一行用逗號 200, 201 =>
break 要自己寫,忘了會 fall-through 不需要,只執行一個分支
沒有相符也沒有 default 什麼都不做 丟出 UnhandledMatchError
每個分支 可以寫很多行 只能是一個運算式

match (true) 和 switch (true) 一樣可以寫範圍判斷。要一個分支裡做很多事,或需要 fall-through 的時候,用 switch 或 if; 只是「依某個值得到另一個值」時,match 比較短,也比較不容易出錯。

match 的四種情況

第 12 行的 $input 是字串 '1':switch 會和 1 相符,match 用 === 比較,所以跳過 1、選中 '1'。最後一段刻意示範沒有相符的分支、也沒有 default:程式以 Fatal error 結束,UnhandledMatchError 的訊息會指出是哪個值。

想一想:switch 與 match

1.

下面的程式會印出什麼?

<?php
$n = 2;
switch ($n) {
    case 1:
        echo 'a';
    case 2:
        echo 'b';
    case 3:
        echo 'c';
        break;
    case 4:
        echo 'd';
}
2.

下面的程式會印出什麼?

<?php
$v = '5';
switch ($v) {
    case 5:
        echo 'A';
        break;
    default:
        echo 'B';
}
echo match ($v) {
    5 => 'A',
    default => 'B',
};
3.

下面的程式執行的結果是什麼?

<?php
$grade = 'C';
$point = match ($grade) {
    'A' => 4,
    'B' => 3,
};
echo $point;
第 1 次作答

動手做:計算停車費

停車場的收費規則如下,請完成程式,印出「車種 停車幾小時:多少元」。

  • 停車 0 小時或負數:印出「時數不正確」
  • 機車(scooter)一律 20 元
  • 汽車(car)每小時 40 元,但超過 5 小時以 200 元計
  • 其他車種:印出「不收這種車」

用 match 把車種換成中文名稱(機車、汽車,其他是 null),再用 if 計算費用。

你的輸出
預期輸出

重點回顧

  • if/elseif/else 由上往下檢查,只執行第一個成立的區塊;範圍大的條件放後面
  • 當成 false 的值:false、0、0.0、""、"0"、[]、null;"0.0"、" "、[0] 都是 true
  • 判斷「是不是空字串」寫 $s !== '',不要只寫 if ($s)(使用者輸入的 "0" 會被當成沒輸入)
  • 巢狀太深時,先處理特殊情況並提早 return
  • 與 HTML 混寫用替代語法 if: … elseif: … else: … endif;
  • switch 用寬鬆比較 ==,相符後會一路往下執行到 break(fall-through);多個 case 可以共用一段程式
  • match(PHP 8.0)用嚴格比較 ===、直接得到一個值、不需要 break;沒有相符又沒有 default 會丟出 UnhandledMatchError
  • switch (true)、match (true) 可以用來判斷範圍
這一課完成了!
Next lesson:迴圈結構
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。