| 課程110:函式的應用 |
摘要:
在課程108撰寫資料庫網頁程式中,在各個網頁程式裡使用了大量相同的程式碼。程式開發者,在開發應用程式的過程當中,如果有碰到《似曾相識》的感覺時,就必須要有重新調整程式結構的警覺。將類似的程式碼,從原本的程式碼中抽離出來,按照功能,獨立成為一個功能模組,避免重複撰寫相同功能的程式碼。模組化的方式有兩種:一、自訂函式;二、物件導向。在這個課程我們先討論如何撰寫自訂的函式,讓程式模組化。然後,改寫原先的資料庫網頁程式。在下個課程中,我們將討論物件導向程式設計。
|
函式
|
說明:
函式,是一個獨立的程式碼區段,只需撰寫一次,就可以讓程式的其他部分,藉由呼叫函式的方式,重複使用。通常,函式會接受參數,執行特定的功能,傳回程式執行的結果。藉由使用函式,可以節省你的程式開發時間,以及減少程式的臭蟲,提高程式的可維護性。
但是,光是把程式碼,寫成函式,並不會讓你的程式變得更好,或是讓你的工作變得更輕鬆。你必須學習養成如何撰寫好的函式。好的函式,通常有以下的特質:
- 最好不超過一頁:太長的函式,通常不好維護,而且容易發生錯誤。
- 函式只執行一個特定的功能:如果,在一個函式裡面,執行多個功能時,通常必須把各功能,再切割成獨立的函式。這樣,才可以更模組化,在主程式組合這些功能時,能更有彈性。
- 好的函式,會有好名字:如果,你無法替你的函式,找出一個好名字的話,通常代表,你對函式的功能,沒有具體的認知。自然無法寫出好的函式。
在這一節中,我們使用範例,來學習如何撰寫函式:
- 函式的語法。
- 參數傳遞。
- 預設參數。
- 函式內變數的範圍。
- 使用 include()函式,來建立自己的函式庫。
|
| 一、函式的語法 |
function 函式名稱([參數1, 參數2, ...參數n]){
程式碼
} |
說明:
- 撰寫函式時,在 function保留字之後,接著是使用者自己命名的函式名稱。函式名稱之後,是由括弧所包含的是要交給函式處理的參數。視情況需要,函式可以接受任何數目的參數,包括不接受任何參數。之後,是由
{ 和 }所包含的程式區段。
- 函式的執行:在主程式呼叫函式之後,自 { 開始由上而下的順序,一直執行到 }為止或碰到 return 的命令句時結束。
- return 可以用來結束函式的執行,return 後面如果有接任何運算式,則會將運算式所得的結果,傳回給主程式。
|
| 範例:無參數,無回傳值 |
程式碼:
<?php
function today(){
$ty = date("Y") - 1911;
echo '民國 '.$ty.'年'.date("m月d日");
}
today();
?> |
| 執行程式 |
| 範例:無參數,有回傳值 |
程式碼:
<?php
function today(){
$ty = date("Y") - 1911;
return'民國 '.$ty.'年'.date("m月d日");
}
echo today();
?> |
| 執行程式 |
| 範例:有參數,有回傳值 |
程式碼:
<?php
function numberOptions($start, $end, $selected){
$option = "";
for($i = $start; $i <= $end; $i++){
$list .= "<option value='$i'";
if($i==$selected){
$list .= " SELECTED";
}
$list .=">$i</option>";
}
return $list;
}
$yr = date('Y') - 1911;
$yr_start = $yr - 5;
$yr_end = $yr + 5;
$mn = date('m');
$dy = date('d');
$yr_option = numberOptions($yr_start, $yr_end, $yr);
$mn_option = numberOptions(1, 12, $mn);
$dy_option = numberOptions(1, 31, $dy);
?>
民國 <select name=year><?php echo $yr_option; ?></select>年
<select name=month><?php echo $mn_option; ?></select>月
<select name=day><?php echo $dy_option; ?></select>日
|
| 執行程式 |
| 二、參數傳遞 |
說明:
當其他部分的程式碼,呼叫函式,以變數當作參數,傳遞給函式時,實際上函式所接受到的是這個變數的值,所以,在函式中的程式碼,如果更改這個變數時,並不會影響到原本程式中的變數。這種參數的傳遞方式,稱之為值的傳遞。
另一種參數傳遞的方式,稱之為參照的傳遞。使用這種方式傳遞參數給函式處理時,當函式更改參數的值,原本程式的變數值也會跟著改變。使用參照傳遞方式,在函式的定義中,參數之前必須加上
&符號。其他程式,呼叫這個函式時,必須在這個參數使用變數,不可以是其他的運算式(如:常數、定數)。 |
| 範例:參照傳遞 |
程式碼:
<?php
function add_by_value($value, $increment){
$value += $increment;
}
function add_by_reference(&$value, $increment){
$value += $increment;
}
$n = 100;
$i = 50;
echo '原本 n 的值: '.$n.'<br />';
add_by_value($n, $i);
echo '值傳遞之後 n 的值: '.$n.'<br />';
add_by_reference($n, $i);
echo '參照傳遞之後 n 的值: '.$n.'<br />';
?>
|
| 執行程式 |
| 三、預設參數 |
說明:
函式使用預設參數時,呼叫函式的程式,可以不需要提供這個參數,而使用函式中所定義的參數預設值。
使用預設參數時,預設參數必須放在非預設參數的後面(右邊)。 |
| 範例:預設參數 |
程式碼:
<?php
function numberOptions($start, $end, $selected=3){
$option = "";
for($i = $start; $i <= $end; $i++){
$list .= "<option value='$i'";
if($i==$selected){
$list .= " SELECTED";
}
$list .=">$i</option>";
}
return $list;
}
$number_options = numberOptions(1, 10);
?>
<select name=number><?php echo $number_options; ?></select>
|
| 執行程式 |
| 四、函式內變數的範圍 |
說明:
函式內所使用的變數,除非特別指定,均為區域變數。區域變數的範圍,只限定在定義這個變數的函式內。函式外即使有同名的變數,因為範圍不同,所以是另一個變數。兩者不會互相影響。
如果,在函式之內有特別指定變數範圍(在變數名稱之前,加上 global 保留字)。變數變成全域變數。 |
| 範例:區域變數及全域變數 |
程式碼:
<?php
function local_scope(){
$x = 5;
}
function global_scope(){
global $x;
$x = 10;
}
$x = 0;
echo '原本 x 的值: '.$x.'<br />';
local_scope();
echo '呼叫 local_scope()函式之後, x 的值: '.$x.'<br />';
global_scope();
echo '呼叫 global_scope()函式之後, x 的值: '.$x.'<br />';
?>
|
| 執行程式 |
| 五、使用 include()函式,來建立自己的函式庫 |
說明:
到目前為止,所有的函式,都是寫在和主程式同一個網頁中,所以,只有這個主程式的網頁可以呼叫這些函式。
更好的做法,是把所有函式按照功能的類別,寫在同一個檔案。然後,在主程式中,使用 include() 或 include_once()
函式,將函式的檔案,含括在主程式中。透過含括檔案的方式,就可以把函式的功能,提供給其他的PHP網頁程式使用。 |
| 範例:使用含括檔案的方式 |
程式碼:
<?php
// 檔名: 110_07.php
function numberOptions($start, $end, $selected){
$option = "";
for($i = $start; $i <= $end; $i++){
$list .= "<option value='$i'";
if($i==$selected){
$list .= " SELECTED";
}
$list .=">$i</option>";
}
return $list;
}
?>
<?php
// 檔名: 110_08.php
include("110_07.php");
$yr = date('Y') - 1911;
$yr_start = $yr - 5;
$yr_end = $yr + 5;
$mn = date('m');
$dy = date('d');
$yr_option = numberOptions($yr_start, $yr_end, $yr);
$mn_option = numberOptions(1, 12, $mn);
?>
民國 <select name=year><?php echo $yr_option; ?></select>年
<select name=month><?php echo $mn_option; ?></select>月
<select name=day><?php echo $dy_option; ?></select>日 |
| 執行程式 |
| |
將函式應用在留言版的資料庫網頁
|
說明:
在這一節當中,我們將原本資料庫中的程式碼,按照功能,將程式碼自原本的程式中抽離,獨立成為個別的函式。
我們按照以下的步驟,來修改留言版的程式:
- 準備工作
- 產生設定檔:config.php
- 產生資料庫函式檔:db.php
- 產生留言版函式檔:guestbook.php
- 修改原本的程式: index.php, add.php, update.php, delete.php
|
| 一、準備工作 |
說明:
將之前109課程所做好的PHP程式,放在另一個新的目錄 guestbook110 之下。 |
| 複製檔案: |
- 使用putty連線到伺服主機。
- 輸入以下的命令,進入 public_html 目錄:
cd public_html
- 輸入以下的命令,產生新的目錄 guestbook110,並將 guestbook109 中所有檔案,
複製到guestbook110:
cp -r guestbook109 guestbook110
|
| 二、產生設定檔:config.php |
說明:
在 config.php 中,我們定義一些有關網站設定的一些變數的資料,方便網站的管理者,修改程式的設定。 |
程式碼:
<?php
/*
檔名: config.php
*/
/* 定義連接資料庫的有關參數 */
$DB_USER = 'lib13';
$DB_PASSWORD = 'mypassword';
$DB_HOST = 'localhost';
$DB_DATABASE = 'lib13';
?> |
| 三、產生資料庫函式檔:db.php |
說明:
在 db.php 檔案中,我們定義資料庫的初始化函式 db_init() ,供網站中所有需要存取資料庫的 PHP 程式使用。任何有關存取這個資料庫的相關功能的函式,都可以在這個檔案中定義。 |
程式碼:
<?php
/*
檔名: db.php
目的: 存放跟整個資料庫操作有關的各函式
*/
include_once("config.php");
function db_init(){
//使用全域變數
global $DB_HOST;
global $DB_USER;
global $DB_PASSWORD;
global $DB_DATABASE;
/* 連接資料庫 */
$link = mysql_pconnect($DB_HOST, $DB_USER, $DB_PASSWORD)
or die('無法連接到資料庫:'.mysql_error());
/* 選用資料庫 */
mysql_select_db($DB_DATABASE)
or die('無法選擇資料庫['.$DB_DATABASE.']:'.mysql_error());
}
?> |
| 四、產生留言版函式檔:guestbook.php |
說明:
guestbook.php 這個檔案,定義了所有跟留言版有關的資料庫操作功能的函式。其他程式要存取有關留言版的資料,只要呼叫這個檔案中的函式即可。 |
程式碼:
<?php
/*
檔名: guestbook.php
目的: 存放跟操作留言版各類功能有關的函式
*/
include_once("db.php");
// 呼叫 db.php 檔案中的 db_init()函式來初始化資料庫
db_init();
function getRecordset(){
// 宣告一個陣列變數 $recordset, 存放查詢所得的紀錄集
$recordset = array();
// 定義 SQL 命令的字串變數
$sql = 'SELECT * FROM Guestbook ORDER BY post_time DESC';
// 傳回查詢結果
$result = mysql_query($sql);
if(!$result) die ('無法執行查詢: '.$sql);
while($record = mysql_fetch_assoc($result)){
array_push($recordset, $record);
}
return $recordset;
}
function Add(){
// 定義 SQL 命令的字串變數
$sql = "INSERT INTO Guestbook(name, email, web, content, post_time)";
$sql .= " VALUES('$_POST[name]', '$_POST[email]', '$_POST[web]', ";
$sql .= "'$_POST[content]', NOW())";
// 執行查詢
return mysql_query($sql);
}
function Retrieve(){
// 定義 SQL 命令的字串變數
$sql = 'SELECT * FROM Guestbook WHERE id='.$_GET[id];
// 執行查詢
$result = mysql_query($sql);
if(!$result) die('執行查詢錯誤: '.$sql);
return mysql_fetch_assoc($result);
}
function Update(){
// 定義 SQL 命令的字串變數
$sql = "UPDATE Guestbook SET name='$_POST[name]', email='$_POST[email]', ";
$sql.= "web='$_POST[web]', content='$_POST[content]' WHERE id=$_GET[id]";
// 執行查詢
return mysql_query($sql);
}
function Delete(){
// 定義 SQL 命令的字串變數
$sql = "DELETE FROM Guestbook WHERE id=".$_GET[id];
// 執行查詢
return mysql_query($sql);
}
?> |
| 五、修改原本的程式: index.php, add.php, update.php, delete.php |
說明:
在這裡,我們使用含括 guestbook.php檔案,並拿掉所有跟資料庫有關的程式碼。藉由呼叫 guestbook.php 當中所定義的函式,執行各網頁程式所需要的功能。下面分別是修改後的各個程式的原始碼: |
| index.php |
| add.php |
| update.php |
| delete.php |
| 執行程式 |