課程111:物件導向程式設計 |
摘要:
在這個課程中,我們將討論物件導向程式設計。首先,我們討論物件導向程式設計的觀念。接著,我們以實例來示範 PHP 物件導向程式設計的撰寫。然後,再把物件導向程式設計的方法,應用在留言版的程式中。 |
物件導向程式設計觀念
|
PHP 支援物件導向程式設計,雖然就純粹的物件導向程式設計的觀點來看,它的支援並不是很完整,但是,只要我們遵循良好的程式設計習慣,我們還是可以善用 PHP ,來開發物件導向的程式。
為什麼要使用物件導向的程式設計?
在 物件導向程式設計的觀念提出之前,軟體開發者,大多是使用結構化的程式設計。所謂結構化的程式設計,就是把問題切割成各個比較小的問題,比較小的問題,如 果還是複雜到無法以一個函式來解決時,就在切割成為更小的問題。直到可以用一個單一的函式來解決為止。每個函式處理個別的功能,主程式藉由呼叫各個函式, 來完成他的工作。
在前一個課程函式的應用, 我們應用了結構化的程式設計,將留言版的功能分割成各個函式,各網頁藉由呼叫各函式的方式,完成存取留言版資料的工作。使用結構化的程式設計,的確簡化了 我們撰寫程式的工作,也提高了程式的可維護性。但是,結構化程式設計在開發大型專案時,還是無可避免的碰到了他的瓶頸。因為,結構化的程式設計,專注於功 能面(函式)的開發,而往往忽略了功能所要處理的資料。被處理的資料與功能在結構化的程式設計是分離的關係。在大型專案的開發上,由於要處理的問題,相對 的要複雜許多,如果,資料與函式之間沒有關聯性,很容易發生錯誤,維護起來也很不方便。後來,物件導向程式設計的興起,就是為了解決,結構化程式設計所面 臨的資料與功能分離的問題。
物件導向程式設計的常用名詞:
- 屬性(Property):即物件裡的資料(變數)。
- 方法(Method):即物件裡的功能(函式)。
- 成員(Member):即類別裡所定義的變數或函式。
- 物件:類別的實例。
- 類別:物件的定義。由使用者所定義的資料型態。
物件導向程式設計的支柱
物件導向程式設計的三大支柱,稱之為 PIE(Polymorphism多變, Inheritance繼承, Encapulation封裝)。由於,PHP目前的版本只支援繼承及封裝,所以,我們在此,僅討論繼承與封裝。
所 謂封裝,就是把功能與資料包裝起來成為一個物件,並定義物件的介面。讓外界的程式,透過物件所提供的介面,來與這個物件溝通。外界的使用者,無須知道,物 件內部如何執行他的作業。只需要知道,如何使用物件的介面,來完成自己的工作即可。所以,設計物件的開發者,日後要更新物件的程式時,只要維持物件的介面 不變,便可以確保,使用這物件的外部程式,不需要改寫,一樣可以執行。而外界程式的開發者,只要遵循不直接存取物件內部的功能及資料,僅透過介面來使用物 件的規則,便可以確保程式執行無誤。
所謂繼承,就是子類別藉由繼承父類別的方式,取得父類別所定義的屬性及方法。通常,父類別會定義通用的屬性及方法,而子類別則延伸父類別定義特定的屬性及方法,以解決特定的問題。
如何使用物件導向程式設計來開發程式
使 用物件導向的方式來開發程式,最主要的關鍵,在於程式設計觀念的改變。之前,我們使用函式來開發留言版的時候,我們著重在於找出留言版應該具有的功能,然 後,按照功能來撰寫對應的函式。外界的網頁程式,把資料餵給這些功能,來完成它的工作。使用物件導向程式設計時,我們必須把程式所企圖解決的問題,看做是 一個獨立的個體。在這個個體中,包含了它應該處理的資料,以及處理這些資料的功能。這些功能是為了處理這些資料所產生的。所以,在撰寫留言版的程式時,我 們要把留言版當作是一個自給自足的個體。把程式所要解決的問題,定義成為個別的個體,這個過程稱之為抽象化(Abstraction)。
當 我們的腦子裡,有了這個個體所需要的資料以及功能後,我們就可以專注於定義這個個體的類別。把個體的資料,定義成類別的屬性;把個體的功能,定義成類別的 方法。在定義類別時,先別管外界的程式如何運作,全心全力專注於如何按照這個個體的需求,寫好這個類別。類別定義完之後,外界的程式,便可藉由物件變數, 來使用這個我們定義的類別(使用者定義的資料型態)。物件導向程式設計,名稱上雖然是物件,但是,實際上,程式設計師大部分的心力,在於找出問題中的個 體,定義這個個體的類別。使用這類別的程式部分,反而花的時間不多。
在下一節中,我們將使用實際的例子,來實作 PHP的物件導向程式設計。
|
PHP 物件導向程式設計實例演練
|
說明:
在這一節中,我們使用範例,來學習如何撰寫類別:
- 類別的語法結構。
- 封裝:定義屬性及方法。
- 使用物件:類別的實例化。
- 繼承。
|
一、類別的語法結構 |
class 類別名稱 [extends][父類別名稱]{
類別的定義
}
|
說明:
- 定義類別時,在 class 保留字之後,是使用者所定義的類別名稱。
- 如果,所定義的類別要繼承其他類別時,需加上 extends 保留字,然後,加上父類別的名稱。否則,省略 extends和父類別名稱。
- 之後是由 { 和 }所包圍的類別定義。在這裡,類別的定義,包括了屬性及方法。
|
二、封裝:定義屬性及方法。 |
class 類別名稱 [extends][父類別名稱]{
// 屬性的定義
var $變數名稱;
// 方法的定義
function 方法名稱([參數列]){
}
}
|
說明:
- 定義類別的個別屬性時,前面必須加 var 保留字。代表這變數是這個類別的屬性。
- 定義屬性時,可以給初始值。
- 定義方法時,規則同函式。
- 在方法中,如果要存取類別的屬性時,必須用 $this->變數名稱 這個格式。變數名稱在這裡,不可以加 $符號。
- 如果,類別中的方法名稱與類別名稱相同時,這個方法稱之為這個類別的建構方法。建構方法在類別被實例化時執行。類別實例化,說白一點,就是在外界的程式中,產生這個類別的物件變數。
|
範例:定義類別 |
<?php /* 檔名:111_01.php 定義 Dog 類別 */
class Dog{ var $food = '骨頭'; var $name;
function Dog(){ echo '產生 Dog 類別的物件時,便會呼叫這個方法(建構方法)'; }
function Eat(){ echo $this->name.'吃'.$this->food; } } ?>
|
三、使用物件:類別的實例化。 |
// 產生物件時 $物件變數名稱 = new 類別名稱;
// 呼叫物件方法或存取屬性時 $物件變數名稱->物件的方法或屬性;
|
說明:
- 要產生物件時,必須以一個變數來存放物件。
- 必須使用 new 保留字來產生物件。產生物件時,會執行這個物件的建構方法。
- 存取物件的屬性或呼叫物件方法時,物件與其成員之間,必須加 ->。
- 物件的屬性之前,不可加 $ 符號。
|
範例:使用物件 |
程式碼:
<?php /* 檔名:111_02.php 使用 Dog 類別 */ // 含括 111_01.php 定義 Dog 類別的PHP檔 include_once('111_01.php');
// 產生 Dog 類別的物件 $mydog = new Dog; $mydog->name = '來福'; echo '<br>'; $mydog->Eat(); ?>
|
執行程式 |
四、繼承 |
說明:
- 當子類別繼承父類別時,子類別取得父類別所有的成員(屬性及方法)。
- 在子類別的方法,要呼叫父類別的方法時,使用 $this->父類別的方法名稱。
- 父類別通常只定義通用的成員。
- 子類別延伸父類別原有的功能,可另行定義專屬於子類別的功能。
- 當父類別的成員改變時,子類別的成員跟著改變。所以,藉著繼承的關係,可以讓我們的程式維護性大為提高。
|
範例:繼承 |
程式碼:
<?php /* 檔名:111_03.php 定義 Pet, Dog, Cat 類別 */
class Pet{ var $food; var $name; var $language;
function Pet(){ echo '產生 Pet 類別的物件時,便會呼叫這個方法(建構方法)'; }
function Eat(){ echo $this->name.'吃'.$this->food; }
function Speak(){ echo $this->name.'說'.$this->language; } }
class Dog extends Pet{ function Dog(){ $this->food = '骨頭'; $this->language = '汪汪'; echo '產生 Dog 類別的物件時,便會呼叫這個方法(建構方法)'; } }
class Cat extends Pet{ function Cat(){ $this->food = '魚'; $this->language = '喵喵'; echo '產生 Cat 類別的物件時,便會呼叫這個方法(建構方法)<br>'; $this->Pet(); }
function showFear(){ echo $this->name.'怕水'; } } ?>
<?php /* 檔名:111_04.php 使用 Dog, Cat 類別 */ // 含括 111_03.php 定義 Pet, Dog, Cat 類別的PHP檔 include_once('111_03.php');
// 產生 Dog 類別的物件 $mydog = new Dog; $mydog->name = '來福'; echo '<br>'; $mydog->Eat(); echo '<br>'; $mydog->Speak(); echo '<hr>'; $mycat = new Cat; echo '<br>'; $mycat->Eat(); echo '<br>'; $mycat->Speak(); echo '<br>'; $mycat->showFear(); ?>
|
執行程式 |
將物件導向程式設計應用在留言版的資料庫網頁
|
說明:
在這一節當中,我們將把物件導向程式設計,應用在留言版的網頁程式中。
我們按照以下的步驟,來修改留言版的程式:
- 準備工作
- 產生網站設定檔:web_config.php
- 產生資料庫類別檔:db.php
- 產生應用程式設定檔:app_config.php
- 產生留言版類別檔:Guestbook.php
- 修改原本的程式: index.php, add.php, update.php, delete.php
|
一、準備工作 |
說明:
將之前110課程所做好的PHP程式,放在另一個新的目錄 guestbook111 之下。然後,在網站的根目錄底下,建立一個 inc 的目錄。存放網站整體各項設定的檔案,以及存取資料庫物件的父類別檔案。
|
複製檔案: |
- 使用putty連線到伺服主機。
- 輸入以下的命令,進入 public_html 目錄:
cd public_html
- 輸入以下的命令,產生新的目錄 guestbook111,並將 guestbook110 中所有檔案,
複製到guestbook111: cp -r guestbook110 guestbook111
- 輸入以下命令,產生新的目錄 inc。用來存放整體網站的設定檔及父類別檔。
mkdir inc
- 輸入以下命令,產生 web_config.php 和 db.php 這兩個檔案。
touch inc/web_config.php inc/db.php
|
二、產生網站設定檔:web_config.php |
說明:
在 web_config.php 中,我們定義一些有關整體網站各含括目錄所需的參數,以及存取資料庫的設定,方便網站的管理者,日後修改網站的設定。
|
程式碼:
<?php /* 檔名:web_config.php 定義各目錄及資料庫參數的常數 */
// 定義網站目錄的設定 define(WEB_DIR, '/home/lib13/public_html/'); define(INCLUDE_DIR, WEB_DIR.'inc/');
// 定義資料庫的設定 define(DB_HOST, 'localhost'); define(DB_USER, 'lib13'); define(DB_PASSWORD, 'mypassword'); define(DB_DATABASE, 'lib13'); ?>
|
三、產生資料庫類別檔:db.php |
說明:
在 db.php 檔案中,我們定義存取資料庫的父類別,供網站中所有需要存取資料庫的類別繼承之用。在這個類別中,我們定義了資料庫連線及選用資料庫的方法 init()。同時,我們也擷取出存取資料庫的通用功能,分別依照功能定義成各種方法。透過繼承這個父類別,其他子類別就可繼承父類別的方法,無須再個別 定義存取資料庫的方法。子類別只需定義,個別類別所需的特定功能。這樣子的做法,一來,減輕修改程式的負擔,提高整個網站程式的維護便利性。二來,要新增 其他類似的資料庫網頁時,可以透過繼承父類別的方式,減少程式碼的撰寫,提高程式開發的效率。
|
程式碼:
<?php /* 檔名:db.php 定義資料庫父類別,供其他需要存取資料庫的類別繼承之用。 */
class DB{ var $add_sql; var $update_sql; var $delete_sql; var $select_sql; var $retrieve_sql;
function DB(){ $this->init(); }
function init(){ mysql_pconnect(DB_HOST, DB_USER, DB_PASSWORD) || die('無法與資料庫建立連結'); mysql_select_db(DB_DATABASE) || die('無法選擇資料庫:'.DB_DATABASE); }
function Add(){ $this->setSQL(); return mysql_query($this->add_sql); }
function Update(){ $this->setSQL(); return mysql_query($this->update_sql); }
function Delete(){ $this->setSQL(); return mysql_query($this->delete_sql); }
function Select(){ $this->setSQL(); return $this->recordset($this->select_sql); } function recordset($sql){ $rs = array(); $result = mysql_query($sql); if($result){ while($record = mysql_fetch_assoc($result)){ array_push($rs, $record); } return $rs; }else{ return false; } }
function Retrieve(){ $this->setSQL(); $result = mysql_query($this->retrieve_sql); if($result and mysql_num_rows($result) == 1){ return mysql_fetch_assoc($result); }else{ return false; } } } ?>
|
四、產生應用程式設定檔:app_config.php |
說明:
app_config.php 這個檔案,定義了有關留言版所有網頁程式的設定。其他留言版的網頁,只需含括這個檔案,便可以使用定義好的各種設定。
藉由使用目錄來存放各相關子系統的方式,可以讓我們網站的功能模組化,日後需要增減功能時,只要新增或刪除目錄即可。在各目錄中,放置個別的 app_config.php 檔,來負責個別子系統的環境設定。這樣可以提昇各模組的可攜性,方便網站程式開發的管理。
|
程式碼:
<?php /* 檔名:app_config.php 定義這個目錄所需的各項設定 */
// 含括網站設定檔 web_config.php include_once('../inc/web_config.php'); ?>
|
五、產生留言版類別檔:Guestbook.php |
說明:
Guestbook.php,定義了留言版所需要使用的類別 Guestbook。Guestbook類別藉由繼承父類別 DB,取得了存取資料庫的通用功能。所以,在這個類別,只要定義專屬於留言版的各種屬性及功能即可。
|
程式碼:
<?php /* 檔名:Guestbook.php 定義 Guestbook 類別 */
// 藉由含括子系統的設定檔,取得網站及子系統的各種設定 include_once('app_config.php');
// 含括父類別 db.php include_once(INCLUDE_DIR.'db.php');
class Guestbook extends DB{ // 定義屬性 / 通常可以用所要存取的資料表的各個欄位,作為這個類別的屬性 var $id; var $name; var $email; var $web; var $content; var $post_time; var $fk_icon;
// 類別的建構方法 function Guestbook(){ $this->DB(); } // setProperties 方法用來連接表單的欄位以及類別的屬性 function setProperties(){ $this->id = $_POST[id]; $this->name = $_POST[name]; $this->email = $_POST[email]; $this->web = $_POST[web]; $this->content = $_POST[content]; }
// setSQL 方法定義存取資料表所需的各個 SQL 命令 function setSQL(){ $this->add_sql = 'INSERT INTO Guestbook "; $this->add_sql .= "(name, email, web, content, post_time) '; $this->add_sql .= "VALUES('$this->name','$this->email','$this->web',"; $this->add_sql .= "'$this->content',NOW())"; $this->update_sql = "UPDATE Guestbook SET name='$this->name', "; $this->update_sql .= "email='$this->email', web='$this->web', "; $this->update_sql .= "content='$this->content' WHERE id=$this->id"; $this->delete_sql = "DELETE FROM Guestbook WHERE id=$this->id"; $this->select_sql = "SELECT * FROM Guestbook ORDER BY post_time DESC"; $this->retrieve_sql = "SELECT * FROM Guestbook WHERE id=$this->id"; } } ?>
|
六、修改原本的程式: index.php, add.php, update.php, delete.php |
說明:
在這裡,我們含括 Guestbook.php檔案。藉由產生 Guestbook的物件 $obj,按照各網頁程式所需要的功能, 透過 $obj物件,呼叫Guestbook所定義及繼承的各個方法。
|
index.php |
add.php |
update.php |
delete.php |
執行程式 |