National Chengchi 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 58 25°C PM2.5 12
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 06

迴圈結構

for、while、do-while、foreach,break 與 continue
Interaction實作 25 minute(s)

Learning Objectives

  • 用 for 寫「跑固定次數」的迴圈,說出初始、條件、更新三個部分各在什麼時候執行
  • 用 while 與 do-while 寫「不知道要跑幾圈」的迴圈,並說明 do-while 至少執行一次
  • 用 foreach 走訪索引陣列與關聯陣列,取出值或同時取出鍵和值
  • 說明 foreach ($a as &$v) 的參照在迴圈結束後仍然存在,用完要 unset
  • 用 break、continue(以及 break 2、continue 2)控制迴圈,並寫出小範圍的巢狀迴圈

同樣的事做很多次

要印出 1 到 100、把購物車裡每一項的金額加起來、把資料庫查到的每一筆資料畫成表格的一列, 這些都是「同樣的步驟重複很多次」。迴圈(loop)讓你只寫一次步驟,讓 PHP 依條件重複執行。

PHP 有四種迴圈:

迴圈 適合
for 知道要跑幾次(從 1 數到 10)
while 不知道要跑幾次,條件不成立就停(存款超過目標為止)
do-while 和 while 一樣,但至少執行一次
foreach 走訪陣列的每個元素(最常用)

逐步執行動畫裡,注意黃色箭頭往回跳的時候:那就是開始下一圈。左邊的變數會顯示每一圈的值。

for 與 while

for ($i = 1; $i <= 4; $i++) 的三個部分:初始 $i = 1 只在開始時執行一次;每一圈開始前檢查條件 $i <= 4,不成立就結束;每一圈結束後執行更新 $i++。動畫裡箭頭回到第 4 行時,就是先做更新、再檢查條件。

無窮迴圈

while 的條件如果永遠成立,迴圈就永遠不會結束:

$n = 1;
while ($n <= 10) {
    echo $n;
    // 忘了寫 $n++:$n 永遠是 1
}

真正的 PHP 遇到這種情況,命令列會一直跑下去,網頁則會跑到 max_execution_time(預設 30 秒)才被中止。 CodeLab 的直譯器有步數上限,超過時會停止並標示「已截斷」。看到這個標示時,先檢查迴圈的條件會不會變成 false: 每一圈有沒有更新條件裡用到的變數、更新的方向對不對(例如該加卻寫成減)。

while (true) 也很常見,它是刻意寫的無窮迴圈,要在迴圈裡用 break 離開(本課後面介紹)。

do-while 至少執行一次

$n 是 10,$n < 5 一開始就不成立:while 一次都不執行,do-while 先執行一次才檢查條件。第二段用 do-while 算整數有幾位數;最後一段改用 while 算 0 的位數,結果是 0 位數,因為迴圈一次都沒有執行。

想一想:for 與 do-while

1.

下面的程式會印出什麼?

<?php
for ($i = 0; $i < 10; $i += 3) {
    echo $i;
}
echo ' ', $i;
2.

下面的程式會印出什麼?

<?php
$x = 5;
do {
    echo $x;
    $x--;
} while ($x > 5);
echo '/', $x;
第 1 次作答

foreach:走訪陣列

走訪陣列最常用 foreach,有兩種寫法:

foreach ($fruits as $f) { … }              // 每一圈把一個「值」放進 $f
foreach ($stock as $name => $qty) { … }    // 每一圈把「鍵」放進 $name、「值」放進 $qty

陣列有幾個元素就跑幾圈,順序是元素加入的順序(第 08 課會詳細介紹陣列)。 range(起點, 終點, 間隔) 會產生一個連續數字的陣列,例如 range(1, 5) 是 [1, 2, 3, 4, 5]、range(10, 0, 5) 是 [10, 5, 0], 可以和 foreach 搭配,取代簡單的 for。

和 if 一樣,迴圈也有替代語法,與 HTML 混寫時常用:foreach (…): … endforeach;, 另外還有 for: … endfor;、while: … endwhile;。

foreach 取值、取鍵和值,以及替代語法

右邊是陣列的內容。每一圈 $f(或 $name、$qty)會換成下一個元素。最後一段用替代語法 foreach: … endforeach; 為每種水果輸出一個 <li>。

在 foreach 裡修改陣列:參照與它的陷阱

foreach 的 $v 是元素的複本,改 $v 不會改到陣列。要直接修改陣列,有兩種寫法:

foreach ($prices as $k => $v) {
    $prices[$k] = $v * 2;          // 用鍵寫回陣列(最安全)
}

foreach ($prices as &$v) {          // & 讓 $v 成為元素的參照(reference)
    $v = $v * 2;
}
unset($v);                          // 用完一定要解除

&$v 表示「$v 就是那個元素本身」,改 $v 等於改陣列。問題在迴圈結束後,$v 仍然連著最後一個元素。 之後如果又寫 foreach ($prices as $v),每一圈把值指派給 $v,等於一直在改最後一個元素。 下面的動畫重現這個經典問題,注意右邊陣列的最後一格。

沒有 unset 的參照:最後一個元素被改掉

第一個迴圈用 &$p 把每個價格乘 2,得到 200,400,600,這部分沒有問題。第二個迴圈沒有 &,但 $p 仍然是最後一個元素的參照:每一圈把值放進 $p,就是放進陣列的最後一格。看右邊陣列的第三格怎麼從 600 變成 200、再變成 400。

break 與 continue

指令 作用
continue 跳過這一圈剩下的部分,直接開始下一圈(for 會先執行更新)
break 立刻結束整個迴圈,跳到迴圈後面的程式
break 2、continue 2 數字表示作用在往外第幾層迴圈:break 2 一次跳出兩層

巢狀迴圈(迴圈裡面還有迴圈)時,外層每跑一圈,內層就從頭跑完一整輪。外層 3 圈、內層 3 圈,內層的內容總共執行 9 次, 圈數相乘,資料一多就會很慢,範例都用小範圍。

switch 也算一層:在迴圈裡的 switch 中寫 break,只會離開 switch,不會離開迴圈;要離開迴圈得寫 break 2。

continue、break、巢狀迴圈與 break 2

第一段印出 1 到 10 的奇數,但超過 7 就停。第二段是九九乘法表的 2、3 兩列:外層 $a 每跑一圈,內層 $b 從 1 跑到 3。第三段在二維陣列裡找 0,找到後用 break 2 同時結束兩層迴圈,不再檢查剩下的元素。

想一想:參照、continue 與 break

1.

下面的程式會印出什麼?

<?php
$a = [1, 2, 3];
foreach ($a as &$v) {
}
foreach ($a as $v) {
}
echo implode(',', $a);
2.

下面的程式會印出什麼?

<?php
for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($j == 2) {
            continue 2;
        }
        echo "{$i}{$j} ";
    }
}
3.

下面的程式會印出什麼?

<?php
for ($i = 1; $i <= 3; $i++) {
    switch ($i) {
        case 2:
            break;
    }
    echo $i;
}
第 1 次作答

動手做:整理溫度紀錄

$temps 是連續幾天的最高溫,-999 表示那天感測器故障,不要算進去。請完成程式:

  1. 逐日印出超過 30 度的日子,格式是「第幾天:幾度」(第一個元素是第 1 天)
  2. 最後印出有效的天數與平均溫度,平均用 round(…, 1) 四捨五入到小數第一位
你的輸出
預期輸出

重點回顧

  • for (初始; 條件; 更新):初始只執行一次,每圈開始前檢查條件,每圈結束後執行更新;初始與更新可以用逗號寫好幾個
  • while 先檢查條件才執行,可能一次都不執行;do { … } while (條件); 先執行再檢查,至少執行一次
  • 條件永遠成立就是無窮迴圈:檢查條件裡的變數有沒有在每一圈更新
  • foreach ($a as $v) 取值、foreach ($a as $k => $v) 取鍵和值;range() 產生連續數字的陣列
  • 迴圈變數在迴圈結束後仍然存在,保留最後一圈的值
  • foreach ($a as &$v) 可以直接修改陣列,用完一定要 unset($v),否則之後再用 $v 會改到最後一個元素
  • continue 跳到下一圈、break 結束迴圈;break 2、continue 2 作用在往外第二層;switch 也算一層
  • 與 HTML 混寫用 foreach: … endforeach;(也有 for: … endfor;、while: … endwhile;)
這一課完成了!
Next lesson:函式
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。