php w3c

PHP 程式設計初探 - 上課教材

PHP 程式設計初探 > 課程內容 > 第 04 章 - 迴圈與陣列初探

第 04 章 - 迴圈與陣列初探

上次更新日期 2020/04/05

我們在第二章講到複選,那個複選的勾選項目是變動的,並非固定值。這個就得要使用陣列配合迴圈來處理! 否則,很不容易抓出需要的項目!另外,有時候,我們也很容易在網頁上面應用許多迴圈,產生我們所需要的環境! 例如網頁配色等等~這一章,就讓我們來嘗試玩一玩迴圈與陣列吧!

學習目標:

  1. 利用 for 迴圈
  2. 利用 while 迴圈
  3. 了解陣列在網頁上的應用
  4. 了解陣列的排序

4.1: 使用 for 迴圈

迴圈很有趣啊!它可以將需要重複進行的動作,透過小小的元件控制,就能夠讓我們的系統幫我們『重複』進行多次! 這樣對於規律的行為,就會變得很有幫助!一般來說, for 迴圈的語法是這樣的:

<?php
	for ( $i = 1; $i <= 10; $i++ ) {
		echo $i ;
	}

	for ( 初始值; 結束條件; 步階 ) {
		在此條件底下要被執行的指令;
	}
?>

最重要的就是起始值、結束值與每個條件的步階 (step) 設定!舉例來說,像我們繳交作業的網頁那樣,如果你需要針對『學號』的資料來排列, 然後共有 50 個學號時,可以這樣嘗試看看:

例題 4.1-1:以迴圈列出學號
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit04-1-1.php,後續將程式碼寫入 body 當中 ;
  2. 檔案最上方需要載入 functions.php 喔!
  3. 在 ul 裡面塞入一段 PHP 程式碼,程式碼裡面需要有:
    • 給予一個變數 $mystart 為 1
    • 給予一個變數 $myend 為 50
    • 使用 for 迴圈,規範變數 $i 從 $mystart 到 $myend 為止
    • for 迴圈內部只要顯示『 <li>4070C0${i}</li> 』之類的資訊即可
  4. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  5. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: for 迴圈初探

很簡單的就將我們需要的學號清單列出來了!這就是迴圈的功能!相當簡單又方便!現在,讓我們來思考一下, 早期有一種網頁顏色稱為『網頁安全色 (請看參考資料)』,這種網頁安全色可以讓網頁開發商在進行某些特殊螢幕的開發時, 會有比較好的效果 (顏色會一樣),雖然目前已經不再需要了。所謂的安全色,就是以 51 數值為步階,在 rgb() 函數裡面使用的顏色, 例如底下的顏色:

  • rgb(0,0,0)
  • rgb(0,0,51)
  • rgb(0,51,0)
  • rgb(51,0,0)

總數會有 0, 51, 102, 153, 204, 255 六個濃度,rgb 三種顏色各有六種濃度,因此得到 6x6x6=216 種色碼!如果要你手動輸入這些色碼, 那你總會手殘的...此時,透過迴圈來處理即可。先來看看,如果要列出 rgb(0,0,0) 到 rgb(0,0,255) 時,要怎麼做?透過表格喔!

例題 4.1-2:使用單層迴圈搭配表格設計出顏色濃度
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit04-1-2.php,後續將程式碼寫入 body 當中 ;
  2. 檔案最上方需要載入 functions.php 喔!
  3. 建立一個表格,以及一個表格橫列 (tr),在橫列裡面建立一隻 PHP 程式
    • 使用 for 迴圈,裡面的 $i 值從 0 到 5 喔,步階就給 1 吧!
    • 先由 $i * 51 計算出 $b1 的變數,然後將變數傳給表格欄位內的色碼塊
    • 在迴圈內輸出『 <td tyle='background-color: rgb(0,0,$b1)'>rgb(0,0,$b1)</td> 』
  4. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  5. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 單層色碼

唉啊~上面的表格內容實在很糟糕!基本上,我們可以使用所謂的『對比色』來處理背景與前景的顏色~上面只有背景 (background-color) 而已, 如果想要加上前景 (color) 時,怎麼設計呢?基本上,如果是 rgb(0,0,0),對比色就是 rgb(255,255,255),也就是三種顏色分別使用 255 去減它, 就會得到該顏色的對比色~因此,請用對比色的概念重新處理上面的範例:

例題 4.1-3:增加 4.1-2 的對比色顯示
  1. 直接取出 /www/php/unit04-1-2.php 的內容來修改
  2. 在 PHP 的程式碼裡面,增加 color 的 style ,內部的 rgb 都使用 255 去減。
  3. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  4. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 單層色碼加上對比色

接下來,我們在上面的基礎上,再加一層迴圈,這次迴圈先使用 RGB 的 G 顏色,亦即 rgb(0,0,0)... rgb(0,51,0)...的格式。 那我們知道每一橫列都需要 tr 才對~所以,在新的一層資料中,就得要將第二組顏色另外使用一個變數來處理,假設為 $j 來處置好了!

例題 4.1-4:將 4.1.3 的資料,在加上另外一層~用雙層迴圈處理!
  1. 將 /www/php/unit04-1-2.php 另存新檔成為 unit04-1-4.php,然後進行修改
  2. 先將原本的 PHP 程式碼圈選之後,按下 [tab] 按鈕往後推一格
  3. 在原本的 PHP 程式碼前,加上一個 for 迴圈,使用 $j 為變數,且與 $i 相同,都從 0 到 5,步階為 1
  4. 增加一個變數名 $g1,其內容為 51*$j 計算出 Green 的顏色濃度
  5. 增加一個變數名 $g2,其內容為 255-$g1,計算出 Green 的對比色濃度
  6. 修改輸出的結果,讓 rgb 內的資料成為含有 $g1 與 $g2 的資料格式
  7. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  8. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 2層色碼加上對比色

既然兩層色碼的問題都解決了,那麼 3 層網頁安全色的色碼也就能夠順利處理掉才對!

例題 4.1-5:將 4.1.4 的資料,在加上另外一層~用雙層迴圈處理!
  1. 將 /www/php/unit04-1-4.php 另存新檔成為 unit04-1-5.php,然後進行修改
  2. 先將原本的 PHP 程式碼圈選之後,按下 [tab] 按鈕往後推一格
  3. 在原本的 PHP 程式碼前,加上一個 for 迴圈,使用 $k 為變數,且與 $i, $j 相同,都從 0 到 5,步階為 1
  4. 增加一個變數名 $r1,其內容為 51*$k 計算出 Red 的顏色濃度
  5. 增加一個變數名 $r2,其內容為 255-$r1,計算出 Red 的對比色濃度
  6. 修改輸出的結果,讓 rgb 內的資料成為含有 $g1 與 $g2 的資料格式
  7. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  8. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 3層色碼加上對比色

簡簡單單的幾個式子,就可以將你需要的整個網頁安全色的 216 個顏色通通顯示出來!而且還能夠使用 table 的樣式來展示, 這樣就會相當愉快!立刻就能處理妥當了!這也是為啥連寫網頁也是需要一些基礎程式設計的能力,會讓你減少很多不必要的工作!

4.2: 使用 while 迴圈

有時候,我們可能會透過迴圈進行某件行為,而這個行為得要透過某個事件才能夠截止。這種情境並不是『固定次數的迴圈』樣式, 因此,使用 for 迴圈會怪怪的。你當然可以持續使用 for 迴圈,然後在程式碼內加上判斷式,不過,那樣的語法不夠直覺,會怪怪的。 所以,此時可能就得要用到 while 迴圈了!while 迴圈的預設語法是這樣的:

<?php
	while (某個條件發生時才進行) {
		在此條件下會被觸發的程式碼;
	}
?>

來玩個假設,如果你想要從 1~100 之間抽出一個幸運數字,這個幸運數字必須要是 30 才行,那抽數字會抽幾次呢? 讓我們來測試一下:

例題 4.2-1:用 while 迴圈計算抽出幸運數字的次數
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit04-2-1.php,後續將程式碼寫入 body 當中 ;
  2. 檔案最上方需要載入 functions.php 喔!
  3. 建立一個 PHP 的程式碼,並且先給予一個 $i 的變數,假設為 0 整數好了;
  4. 設定一個名為 $myluck 的變數,內容先指定為 0 好了
  5. 設計 while 迴圈,當 $myluck 為 30 時,就給予停止
  6. 在當中的程式碼: (1) $i=$i+1; (2) $mylock = rand(1,100); (3)清單類型的顯示次數與 $myluck 數值
  7. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  8. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 用迴圈持續抽幸運數字

上面的範例是計算抽到 30 這個數值的次數,那能不能轉過來,例如很多時候都要有抽籤的活動,能不能抽出 3 個幸運觀眾!? 就是抽三次,從一定的範圍內抽出來~那應該是可以的:

例題 4.2-2:用 while 迴圈,從一定的範圍內 (讓用戶輸入範圍) 並抽出特定的次數 (由使用者自行設定人次)
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit04-2-2.php,後續將程式碼寫入 body 當中 ;
  2. 檔案最上方需要載入 functions.php 喔!
  3. 先在 body 當中顯示一個表單,此表單要傳送給自己操作,使用 post 的方法,表單名稱就寫 myform
    1. 表單內建立三個變數,第一個是 mystart 變數,使用 text 類型,第二個是 myend 變數,使用 text 類型, 第三個則是 mynu 變數,同樣使用 text 類型。它們分別是開始、結束與個數的相關資訊。
    2. 建立一個 submit 的按鈕,可以填寫『開始抽獎』之類的文字說明
    3. 這個部份完成之後的半成品,應該是有點類似這樣: 抽抽樂-表單部份
  4. 開始從表單將資料抓出來!在最上方使用 $_REQUEST 將三個變數嘗試抓出來!
    1. 先建立一個變數,名為 $myact ,預設內容為 no
    2. 使用條件判斷,若存在 $_REQUEST['mystart'] 時,就抓下 $mystart, $myend, $mynu 變數,並將 $myact 設定為 yes。
    3. 撰寫完畢之後,你可以使用 echo 的方式,將上面的變數顯示到網頁上,並且執行一次上傳的動作看看結果如何。
    4. (option)可以的話,使用條件判斷,將三個 input 的上傳值,重新填回表單中 (value="")
  5. 最後,就開始使用 rand 來抽獎咯!
    1. 使用條件判斷,當 $myact 為 yes 時,才進行所有動作:
    2. 顯示開始抽獎的 h2 標題
    3. 顯示 ul 清單
    4. 設定 $i 為 0
    5. 使用 while 迴圈,條件有兩個,兩個都成立才會跑。一個是 $i 要小於 $mynu,另一個則是防呆用, $i 要小於 100 !這兩個條件同時成立 (&&) 時, 就進入迴圈階段
    6. 讓 $i 長大 ($i++ 或 $i=$i+1)
    7. 顯示清單項目,類似:『echo "<li>" . (rand($mystart, $myend)) . "</li>";』
    8. 脫離迴圈之後,最後顯示 /ul 的清單結束。
  6. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  7. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 抽抽樂!

為了避免使用者惡搞,通常我們在設計程式的時候,都會預先想到一些『防呆』的機制。以上面的設計來說,當使用者輸入要找尋 10000 個使用者資訊時, 我們就只會輸出前面 100 筆,因為程式有防呆!擔心使用者來惡搞啊!這些都是需要考慮的!避免到時候系統被亂用喔!

4.3: 使用陣列功能

以上面的範例來說,我要找出幾筆數據,那如果這幾筆數據有重複怎麼辦?例如,抽獎的結果,兩個人重複怎麼辦?另外, 一般來說,人名或者是學號,可能不會重複啊~那怎麼用 rand 來抽?有問題啊!此外,我們第二章提到的複選,不是也有一堆資料要輸出? 如果不使用陣列,恐怕還很難輸出正確的資訊哩!

  • 陣列的使用

基本上,就如同之前說得,陣列跟我們國中時候學的 f(x) = y 有關,在 PHP 的情境下,所謂 f() 就是陣列, x 就是索引值,y 就是每個索引對應的內容。 一般來說,索引值通常是從 0 開始編號,不過,索引也能夠使用字串來代替!這相當有趣!那陣列如何設定呢?使用底下的語法就可以設定一維陣列:

	// 底下的方式會產生 $array[0], $array[1] 與 $array[2] 的陣列
	$array[] = 1;
	$array[] = 2;
	$array[] = 3;

	// 底下的方式直接給予索引值
	$array[1] = 1;
	$array[2] = 2;
	$array[3] = 3;

也就是說,索引不見得一定要從 0 開始!不過,最好還是從 0 開始編號 (如果是數值的話),這樣在處理上面比較好解決。 現在,讓我們回到第二章點餐的那個習題,搞一下如何使用簡易的陣列吧!

例題 4.3-1:陣列初探
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit04-3-1.php,後續將程式碼寫入 body 當中 ;
  2. 檔案最上方需要載入 functions.php 喔!
  3. 建立名為 $myfood 的 PHP 陣列,然後設定至少 5 個以上的餐點名稱;
  4. 建立一個表單,表單使用 post 方法,傳送給自己處理,名稱就定為 myform
  5. 在表單內建立一個 for 或 while 迴圈皆可,將所有的陣列內容列出,注意, checkbox 需要有 value 以及 name 喔! name 可以都指定為 myfood[] 即可。
  6. 增加一個 submit 的送出按鈕
  7. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  8. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 用陣列設計表單

因為在底下的資料是重複輸出的 (input 的部份),所以未來要修改內容時,只要處理最上方的陣列內容,一切就搞定了! 相當舒服啊~那麼,如何將資料上傳後讀出呢?也是 OK 的!

例題 4.3-2:輸出陣列的結果
  1. 將 /www/php/unit04-3-1.php 另存新檔成為 unit04-3-2.php,然後進行修改
  2. 在 $myfood 陣列之後增加一個名為 $myact 的變數,預設值為 no ,作為是否運作資料下載的依據
  3. 提供一個條件判斷,若有 myfood 的上傳變數存在時,就進行
    1. 將 $myact 設定為 yes;
    2. 使用 $myselect 變數,設定內容為取得 myfood 的資料。
  4. 在表單後面增加一個條件判斷,當確認 $myact 為 yes 時,就進行
    1. 顯示標題『你的選擇』
    2. 顯示 ol 項目
    3. 設定迴圈,迴圈設定為 $i 從 0 到 $i 小於 $myselect 陣列個數,步階為 1
    4. 迴圈內執行顯示清單,清單項目為 $myselect[$i] 這樣的內容
    5. 最終顯示 /ol 結束即可。
  5. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  6. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 用陣列設計表單

上面的問題是,並沒有顯示你之前勾選的複選項目,這樣我無法確認之前是否勾選該項目啊~那可以在 checkbox 的顯示過程中, 增加判斷是否有該項目的功能嘛?應該也是可以的:

例題 4.3-3:使用雙重迴圈判斷兩個陣列的值
  1. 將 /www/php/unit04-3-2.php 另存新檔成為 unit04-3-3.php,然後進行修改
  2. 在表單的 for 迴圈內,新增一個變數,名稱為 $mycheck,預設值為空值;
  3. 增加一個 for 迴圈,使用 $j 變數,預設為 0 到小於 $myselect 陣列個數,步階為 1
  4. 在迴圈內判斷,若 $myfood[$i] 相等於 $myselect[$j] 時,就將 $mycheck 重新設定為 "checked='checked'" 這樣
  5. 在輸出 input 的程式碼中,增加 $mycheck 在 input 標記內
  6. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  7. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 用表單設計陣列

如果今天你是想要從幾個項目中選出一個來食用呢?這個時候,你就可以透過亂數隨機的方式來產生唯一的項目了!

例題 4.3-4:增加隨機亂數的功能,讓系統幫你選擇
  1. 將 /www/php/unit04-3-3.php 另存新檔成為 unit04-3-4.php,然後進行修改
  2. 將原本你的選擇的部份修改掉,增加一變數,假設為 $i 好了,內容為 0 到 myseleclt 陣列數少 1 的範圍 (0,個數-1)
  3. 秀出 $myselect[$i] 即可!
  4. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  5. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 用表單設計陣列

其實意思很簡單,就是你勾選的項目有幾個,從那幾個挑選一個出來的意思!就這麼簡單喔! ^_^!

4.4: 使用 PHP 陣列排序

大略知道怎麼設計迴圈與陣列之後,再來就是需要進行一些有趣的設計了!在很多場合,我們都會推派代表。 代表的名單都有個號碼,那麼,如何抽出這些號碼呢?可以透過 4-2-2 的範例來修改!畢竟那個也是抽出幸運數字! 概念上差不多!另外,任何時刻考慮使用者可能是個白痴或者想要故意玩你的高手,都是個好習慣!因此,我們同樣設計一個防呆。

  • 使用 break 離開迴圈

我們可能會使用到 for 迴圈,但是 for 迴圈裡面並不像 while 可以透過條件控制來離開迴圈,因此,這時我們就要主動加入一個 break 的語法, 強迫跳出迴圈!基本語法是這樣的:

<?php
	for ( ... ) {
		...;
		break;
	}
?>

當程式碼遇到 break 時,就會離開 for 或者是某個迴圈,而直接跳脫出去!可以避免被迴圈搞死喔!

例題 4.4-1:抽出幸運的座號
  1. 將 /www/php/unit04-2-2.php 另存新檔成為 unit04-4-1.php,然後進行修改
  2. 將表單的部份,號碼的部份改為開始座號、結束座號、抽出個數等等,其餘不變!
  3. 在按下送出之後,來到檔案的最上方的 PHP 部份,原本的項目為直接丟入 rand 的亂數結果,這次, 我們透過一個名為 $myok[] 陣列,將所有的抽籤名單通通放入這個陣列裡面。因為人數是固定的, 所以 (1)使用 for 迴圈,規範次數由 0 到 $mynu - 1 次; (2)將抽籤的結果帶入陣列內 (3)如果次數超過 100 次, 就予以離開 (請用上 break 喔!)。
  4. 最終判斷有 $myact 時,就直接以 for 迴圈,將抽籤到的次數貼到螢幕上即可,這部份與例題 4-2-2 相同!
  5. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  6. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 抽出幸運 (不幸) 座號
  • 用陣列在子迴圈裡面進行比對與排除

上面這個案例基本上跟 4-2-2 完全一樣!只是帶入了陣列的用法而已~沒什麼了不起。但是,如果你重複執行幾次這個腳本, 會發現到,慘了!怎麼名單會重複!尤其越少座號時,名單的重複情況會越嚴重!那有沒有辦法克服呢? 可以的!就透過子迴圈 (雙重迴圈) 來處理即可。但是,子迴圈總是需要有個比對的基準,那就是剛剛紀錄下來的陣列的功能了!

例題 4.4-2:抽出幸運的座號-不會重複的版本
  1. 將 /www/php/unit04-4-1.php 另存新檔成為 unit04-4-2.php,然後進行修改
  2. 在抽籤的最外層 for 迴圈,重新更改一下相關的項目:
    • A. 先設定好,若次數大於 100 次時,就脫離外部迴圈
    • B. 設定好一個變數,假設名為 $mygo,目的是用在底下的 while 迴圈當中
    • C. 設定 while 迴圈,條件為 $mygo 為 yes 就進行內部的迴圈條件
    • C.1. 先設定好一個變數,假設為 $mytemp 好了,這個變數的目的是為了抽籤!
    • C.2. 再來開始測試,如果 $myok 的次數不是 0 ,就進行 C.3 的動作,否則就進行 C.4 的動作
    • C.3.a. 設定一個判斷條件的變數,假定為 $mycheck,而且預設值為 yes,亦即沒有與既有的名單重複的意思
    • C.3.b. 設定內部迴圈,條件使用 for 迴圈,透過 $j=0 到 $j<count($myok) 來判斷是否要處理
    • C.3.c. 如果 $mytemp 有等於任何一個 $myok[$j] 時,就設定 $mycheck 為 no
    • C.3.d. 離開 for 迴圈之後,增加一個條件判斷式,(1)如果 $mycheck 為 yes 時,就設定 $myok[$j] 為 $mytemp, (2)同時設定 mygo 為 no,並且 (3)break 掉這次的 while 迴圈
    • C.4. 因為還沒有設定過 $myok,所以設定 $myok[0] 為 $mytemp 囉!
  3. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  4. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 抽出幸運 (不幸) 座號-名單不重複版本
  • 陣列的排序

若程式語言沒有提供陣列的排序時,過去有所謂的泡沫排序法、插入排序法等等,那都需要一些程式碼的運作,才有辦法將陣列的內容進行排序。 不過,PHP 已經有提供陣列的排序功能,簡單排序功能有這些函數:

  • sort($array):可以進行數字的增加排序、或者是文字的遞增排序
  • rsort($array):可以進行數字或文字的遞減排序

我們還沒有講到陣列的索引 (index),所以這裡先知道 sort 與 rsort 即可!現在,讓我們修改上面的案例,增加排序的行為,讓最終輸出時,可以將名單排列整齊

例題 4.4-3:抽出幸運的座號-名單有排序
  1. 將 /www/php/unit04-4-2.php 另存新檔成為 unit04-4-3.php,然後進行修改
  2. 只要將最後的 $myok 的結果,丟改 sort 處理即可。
  3. 最終將程式碼寫入到後面的 pre 當中,以備查驗
  4. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 抽出幸運 (不幸) 座號-名單不重複版本

當然啦,須不需要進行排序是因人而異,畢竟有時候我們需要抽出的是有幸運順序的情況,那就不能用座號排序囉! 如果只是要抽出一群人,並沒有比重的原因,那用這方案,還挺方便的! ^_^

4.5: 小小挑戰題

以迴圈的方法列出九九乘法表的樣式,基本上,你可以列出 2~9 共 8 個方塊,這 8 個方塊格式可以固定。 在每個方塊裡面再以表格的方式條列出 99 乘法表的乘法結果,就可以得到還不錯的效果了。檔名請設定為 unit04-5-1.php, 做完請在 PHP 首頁增加一個連結喔!

九九乘法表

4.6: 參考資料