PHP5與MySQL5 入門學習指南 凱文瑞克 著 第 17 章 物件
本章大綱 17-1 類別 17-2 建構子與解構子 17-3 繼承 17-4 abstract 與 interface 17-5 例外處理 問題與討論
17-1 類別(CLASS) 物件是一個實體, 內容包含了“資料成員”以及“成員函數”來表示一個實體所代表的意義。 類別是虛擬的宣告資料型態。
顏色= 長度= 寬度= 類別 顏色= 灰色 長度= 10 寬度= 10 顏色= 紅色 長度= 10 寬度= 5 顏色= 藍色 長度= 5 長度= 10 寬度= 5 顏色= 藍色 長度= 5 寬度= 10 物件 物件是一個實體, 每一個實體會因為不同的屬性而與其他實體有所不同。
類別 類別中包含: 資料成員 (data member) 表達物件的表徵, 換句話說, 也就是物件的特性。例如:外觀、顏色、重量、名稱或識別號等等, 能夠表現一個物件的特徵及其性質。 成員函數 (member function)。 成員函數就是用來表現物件的行為或者更改資料成員等等。 類別僅僅只是一種資料型態的定義, 也可以說是另一種自己定義的資料型態。物件是由依類別的定義產生的實體, 物件是實體的而類別是虛擬的。
類別格式 類別是一種虛擬的資料的型態, 他的宣告方式如下: class 類別名稱 { var 變數1 ; //物件資料成員的宣告 var 變數2 ; ... function 成員函數一 //物件成員函數之宣告 { ... } function 成員函數二 { ... } }
物件範例 1: <?php 2: class car { 3: var $color ; 4: function set_color($c){ 5: $this->color=$c ; 6: } 7: function get_color(){ 8: return $this->color ; 9: } 10: } 11: ?> 12: <html> 13: <title>物件</title> 14: <body> 15: <?php 16: $MyCar=new car ; 17: $MyCar->set_color("寶藍色") ; 18: echo "車子的顏色是" . $MyCar->get_color() ; 19: ?> 20: </body> 21: </html> 物件範例
第 3 行宣告一個物件資料成員 $color, 以表示車輛的顏色。 1: <?php 2: class car { 3: var $color ; 4: function set_color($c){ 5: $this->color=$c ; 6: } 7: function get_color(){ 8: return $this->color ; 9: } 10: } 11: ?> 第 2-10 行宣告一個類別 car。 第 3 行宣告一個物件資料成員 $color, 以表示車輛的顏色。 第 4-6 行宣告一個物件成員函數為 set_color(), 其功能是設定 $color 資料成員。其中 $this 表示本物件, $this->color 表示本物件中的 $color 資料成員。 第 7-9 行宣告一個成員函數為 get_color(), 這個成員函數被呼叫後會傳回物件中 $color 資料成員的值。
12: <html> 13: <title>物件</title> 14: <body> 15: <?php 16: $MyCar=new car ; 17: $MyCar->set_color("寶藍色") ; 18: echo "車子的顏色是" . $MyCar->get_color() ; 19: ?> 20: </body> 21: </html> 第 16 行利用 new 產生一個 car 的實體物件, 物件名稱為 $MyCar。當物件一旦產生後便含有一個資料成員 $color、二個成員函數 set_color()、get_color()。第17行利用 set_color() 成員函數設定物件$ MyCar的 $color 資料成員為“寶藍色”。第 18 行利用 get_color() 成員函數取得 $color 的值並顯示出來。
物件的操作 物件操作成員函數時必須用 “->” 指定那一個成員函數。格式如下: 物件->資料成員 物件->成員函數 相同類別的物件都是由同一個類別產生出來的, 因此相同類別的物件就會有名稱相同的資料成員及成員函數。 例: $HisCar->set_color(“紅色”) ; 表示$HisCar物件的set_color()函數
簡易購物車範例 類別宣告 物件使用 1: <?php 26: <html> 2: class cart { 3: var $item ; 4: var $total ; 5: function AddOneItem($name,$cost){ 6: $this->item[]=$name ; 7: $this->item[]=$cost; 8: } 9: function GetItem(){ 10: $c=count($this->item); 11: for ($i=0; $i<$c; $i+=2){ 12: echo "項目 : ".$this->item[$i]; 13: echo " => 金額 : ".$this->item[$i+1]." 元<br>"; 14: } 15: } 16: function sum() { 17: $c=count($this->item); 18: $s=0; 19: for ($i=1; $i<$c; $i+=2){ 20: $s+=(integer)$this->item[$i]; 21: } 22: return $s; 23: } 24: } 25: ?> 26: <html> 27: <title>物件應用</title> 28: <body> 29: <?php 30: $customer1=new cart ; 31: $customer2=new cart ; 32: $customer1->AddOneItem("主機板","3000") ; 33: $customer1->AddOneItem("顯示卡","800") ; 34: $customer1->AddOneItem("記憶體","1800") ; 35: $customer2->AddOneItem("PC遊戲","2500") ; 36: $customer2->AddOneItem("滑鼠","100") ; 37: $customer2->AddOneItem("無線網路卡","2500") ; 38: $customer2->AddOneItem("LCD顯示器","8000") ; 39: echo "第一位顧客採購內容: <br>"; 40: $customer1->GetItem(); 41: echo "<hr>" ; 42: echo "第二位顧客採購內容: <br>"; 43: $customer2->GetItem(); 44: echo "<hr>"; 45: $total=$customer1->sum()+$customer2->sum(); 46: echo "今日營業額 $total 元"; 47: ?> 48: </body> 49: </html> 類別宣告 物件使用 簡易購物車範例
1: <?php 2: class cart { 3: var $item ; 4: var $total ; 5: function AddOneItem($name,$cost){ 6: $this->item[]=$name ; 7: $this->item[]=$cost; 8: } 9: function GetItem(){ 10: $c=count($this->item); 11: for ($i=0; $i<$c; $i+=2){ 12: echo "項目 : ".$this->item[$i]; 13: echo " => 金額 : ".$this->item[$i+1]." 元<br>"; 14: } 15: } 16: function sum() { 17: $c=count($this->item); 18: $s=0; 19: for ($i=1; $i<$c; $i+=2){ 20: $s+=(integer)$this->item[$i]; 21: } 22: return $s; 23: } 24: } 25: ?> 第 2-24 行宣告一個購物車的類別 cart。 第 3-4 行宣告二個資料成員, 採購項目及金額 $item, 總採購金額 $total。 第 5-8 行增加一項採購物品。 請注意每次是存入採購項目及金額二個內容, 所以陣列中第 i 及 i+1 項表示第 k 筆採購物品。第 9-15 行顯示所有採購物品。 因為不知道一購有幾個物品, 所以利用 count() 函數取得陣列內容的數量。 第 11 行設定迴圈由 0 開始, 因為以二個陣列內容為單位, 所以迴圈每次加 2。 第 12-13 行顯示採購項目及金額。 第 16-23 行計算採購車之總金額。
26: <html> 27: <title>物件應用</title> 28: <body> 29: <?php 30: $customer1=new cart ; 31: $customer2=new cart ; 32: $customer1->AddOneItem("主機板","3000") ; 33: $customer1->AddOneItem("顯示卡","800") ; 34: $customer1->AddOneItem("記憶體","1800") ; 35: $customer2->AddOneItem("PC遊戲","2500") ; 36: $customer2->AddOneItem("滑鼠","100") ; 37: $customer2->AddOneItem("無線網路卡","2500") ; 38: $customer2->AddOneItem("LCD顯示器","8000") ; 39: echo "第一位顧客採購內容: <br>"; 40: $customer1->GetItem(); 41: echo "<hr>" ; 42: echo "第二位顧客採購內容: <br>"; 43: $customer2->GetItem(); 44: echo "<hr>"; 45: $total=$customer1->sum()+$customer2->sum(); 46: echo "今日營業額 $total 元"; 47: ?> 48: </body> 49: </html> 第 30-31 行宣告二台購物車 customer1 和 customer2。 第 32-34 行設定 customer1 三個採購項目。 第 35-38 行設定 customer2 四個採購項目。 第 39-44 行利用 GetItem() 成員函數分別顯示 customer1, customer2 的採購項目於網頁上。 第 45-46 行計算總營業額, 也就是二台購物車的金額和。
宣告資料成員與成員函數 限制可使用變數及函數的範圍 Public (公用): Private (私有): Protected (保護): 可以在類別內、外任意使用不受限制, 並可以被子類別所繼承。 Private (私有): 只能在類別本身內部使用, 不可以被子類別繼承。 Protected (保護): 只能在類別本身內部使用, 可以被子類別繼承使用。但是類別外無法使用。 class 類別名稱 { public 變數1 ; //物件資料成員的宣告 protected 變數2 ; private 變數3 ; function 成員函數一 //物件成員函數之宣告 { ... } function 成員函數二 }
17-2 建構子與解構子 建構子 解構子 建構子主要的功能是在於當 new 指令產生新物件時就會執行建構子的內容。 將需要預先設定或處理的程式都寫在建構子這個成員函數中 建構子的名稱必需和類別的名稱相同或是在 PHP 5 中可以使用 __construct() 函數 解構子 解構子用於刪除物件時執行的動作。 PHP 5 定義解構子為 __destruct() 。
此行可改成 function __construct() 1: <?php 2: class car { 3: var $color ; 4: function car() { 5: $this->color="紅色" ; 6: } 7: function set_color($c){ 8: $this->color=$c ; 9: } 10: function get_color(){ 11: return $this->color ; 12: } 13 } 14: ?> 15: <html> 16: <title>物件的建構子</title> 17: <body> 18: <?php 19: $ACar=new car ; 20: $ACar->set_color("寶藍色") ; 21: echo "A車顏色是".$ACar->get_color()."<p>" ; 22: $BCar=new car ; 23: echo "B車顏色是".$BCar->get_color() ; ; 24: ?> 25: </body> 26: </html> 此行可改成 function __construct() 第 2 行到第 13 行是宣告一個類別 car。第 4-6 行的 function car() 是這個類別的建構子。在第 5 行中設定了 $color 的值為紅色。 建構子的使用
解構子的應用 1: <?php 2: class test { 3: private $val; 4: function __construct() { 5: $this->val=10; 6: echo "物件產生 <p>"; 7: } 8: public function get_val(){ 9: return $this->val; 10: } 11: function __destruct(){ 12: echo "<p>刪除物件 <p>"; 13: echo "<hr width=50% align=left>"; 14: } 15: } 16: $a=new test; 17: echo $a->get_val(); 18: ?> 第 11-14 行定義解構子。當物件消失時會顯示提示文字並加上一條分格線。 解構子的應用
17-3 繼承 繼承就是一個類別可以承接另一個類別的成員函數與資料成員。 被繼承的類別就稱之為父類別, 另一個就稱之為子類別。 子類別不需宣告就可以擁有父類別的資料成員與成員函數。 extends 定義二個類別繼承的關係。格式如下: class 子類別 extends 父類別
父類別 子類別 子類別不需宣告就可以擁有父類別的資料成員與成員函數
class child extends parent { function get_blood_type(){ class parent { var $blood_type ; } class child extends parent { function get_blood_type(){ return $this->blood_type ; 兩個類別分別是 parent 和 child。在 parent 類別中定義了$blood_type 這個資料成員變數, child 類別利用 extends 宣告 child 是繼承 parent 類別。一旦繼承之後 child 就擁有 parent 定義的資料成員和成員函數。例如在 child 類別中並沒有 $blood_type 資料成員, 但是繼承了 parent 類別中 $blood_type, 因此在 child 類別中是可以使用 $blood_type 資料成員。
繼承應用 1: <?php 2: class car { 3: var $color ; 4: function car() { 5: $this->color="紅色" ; 6: } 7: function set_color($c){ 8: $this->color=$c ; 9: } 10: function get_color(){ 11: return $this->color ; 12: } 13: } 14: class RV extends car { 15: function show_drive($n){ 16: echo $n."輪驅動" ; 17: } 18:} 19: ?> 20: <html> 21: <title>物件的繼承</title> 22: <body> 23: <?php 24: $JohnCar=new car ; 25: $JohnCar->set_color("寶藍色") ; 26: echo "John車子的顏色是".$JohnCar->get_color()."<p>" ; 27: $MaryCar=new RV ; 28: echo "Mary車子是" ; 29: $MaryCar->show_drive(4) ; 30: echo ",顏色是".$MaryCar->get_color() ; 31: ?> 32: </body> 33: </html> 繼承應用
1: <?php 2: class A { 3: function __construct(){ 4: echo "我是類別A的建構子 <p>"; 5: } 6: } 7: class B extends A{ 8: function noop(){ 9: echo "我是類別B的成員函數 <p>"; 10: } 11: } 12: class C extends B{ 13: function noop(){ 14: echo "我是類別C的成員函數 <p>"; 15: } 16: } 17: $i=new A; 18: $j=new B; 19: $k=new C; 20: ?> 很明顯的類別 B 和類別 C 都沒有宣告自己的建構子, 類別 A 宣告自己的建構子。 緊接著產生三的物件 $i, $j, $k。 $i 因為是類別A的物件所以會執行建構子。 $j 是類別 B 的物件, 因為類別 B 本身沒有建構子, 但是類別 B 繼承類別 A, 所以會執行類別 A 的建構子。 相同的道理, $k 沒有建構子, 沿著繼承的關係找到類別 A, 然後執行建構子。
final 的使用 如果一個類別不想被其他的類別所繼承, 則可以宣告為 final 類別。 例如: final class last { ... }
17-4 abstract 與 interface 抽象宣告 (abstract) 例如: 可以使用在類別及成員函數。 如果有一個類別或是成員函數是需要繼承的類別宣告使用的, 在父類別中就可以宣告成抽象宣告。 例如: abstract class car { private $color ; abstract function get_color(); abstract function show_color(); }
1: <?php 2: abstract class car { 3: protected $color ; 4: abstract function get_color(); 5: abstract function set_color($n); 6: } 7: class mycar extends car { 8: private $weight=1500; 9: function get_color(){ 10: return $this->color; 11: } 12: function set_color($newcolor){ 13: $this->color=$newcolor ; 14: } 15: function get_weight(){ 16: return $this->weight; 17: } 18: } 19: $a=new mycar ; 20: $a->set_color("紅色") ; 21: echo "車身是".$a->get_color()."<p>"; 22: echo "車重是".$a->get_weight()."公斤<p>"; 13: ?> 第 2-6 行宣告一個抽象類別 car 其中定義一個 $color 及二個抽象成員函數。第 7-18 行定義類別 mycar 。因為 mycar 繼承 car 因此其中第 9-14 行是實作抽象函數 get_color() 與 set_color()。第 8, 15-17 行則是 mycar 自己 定義的內容。
例如: class 類別名稱 implements 第一個 interface, 第二個 interface,... 一種資料型態的宣告, 它就像是一個類別之間溝通的橋樑。 interface 可以宣告很多的成員函數成為一個資料的型態。 interface 無法產生一個 interface 的實體物件, 由類別實作 (implements) 後才會真實的撰寫成員函數的內容。 例如: class 類別名稱 implements 第一個 interface, 第二個 interface,...
1: <?php 2: interface width { 3: public function get_width(); 4: public function set_width($w); 5: } 6: interface area { 7: public function get_area(); 8: public function get_around(); 9: } 10: class squareA implements width { 11: private $w; 12: public function get_width(){ 13: return $this->w; 14: } 15: public function set_width($newW){ 16: $this->w=$newW ; 17: } 18: } 19: class squareB implements width, area { 20: private $w; 21: public function get_width(){ 22: return $this->w; 23: } 24: public function set_width($newW){ 25: $this->w=$newW ; 26: } 27: public function get_area(){ 28: return $this->w * $this->w; 29: } 30: public function get_around(){ 31: return 4*$this->w; 32: } 33: } 34: $a=new squareA; 35: $a->set_width(10); 36: echo "方形 A 邊長是 ". $a->get_width()."<p>"; 37: $b=new squareB; 38: $b->set_width(30); 39: echo "方形 B 邊長是 ". $b->get_width()."<br>"; 40: echo "方形 B 面積是 ". $b->get_area()."<br>"; 41: echo "方形 B 周長是 ". $b->get_around()."<br>"; 42: ?>
17-5 例外處理 在 PHP 5 中已經支援例外處理。 例外處理是由 try{} 和 catch{} 二個區塊組成, 在 try 區塊中放置的是被監控的程式碼, catch 區塊則是發生例外時抓取錯誤的處理 Exception 是 PHP 處理例外的類別
第 7-10 行抓取例外錯誤。 第 8 行取得並顯示例外物件的錯誤訊息。第 9 行結束程式。 1: <?php 2: try { 3: $filename="abc.php"; 4: if (!file_exists($filename)){ 5: throw new Exception("發生例外錯誤: 檔案不存在!!"); 6: } 7: } catch (Exception $e) { 8: echo $e->getMessage(); 9: exit(); 10: } 11: echo "程式繼續執行"; 12: ?> 第 2-6 行是被監控的程式碼。第 3 行設定 $filename 為一個不存在的檔案名稱 abc.php。第 4 行檢查檔案是否存在。第 5 行如果檔案不存在則利用 throw 將一個錯誤訊息丟到例外處理。在產生例外時設定錯誤訊息為 "發生例外錯誤: 檔案不存在!!"。 第 7-10 行抓取例外錯誤。 第 8 行取得並顯示例外物件的錯誤訊息。第 9 行結束程式。
要處理多個例外的發生就要考慮採用繼承的方式來取得多次例外錯誤的抓取。 1: <?php 2: class extends Exception{ 3: function __construct($f){ 4: echo "發生例外錯誤: 檔案 ".$f." 不存在!!"; 5: } 6: } 7: class myEmptyFile extends Exception{ 8: function __construct($f){ 9: echo "發生例外錯誤: 檔案 ".$f." 是空檔案!!"; 10: } 11: } 12: function checkfile($filename){ 13: try { 14: if (!file_exists($filename)){ 15: throw new myFileNotExist($filename); 16: } 17: if (filesize("empty.txt")==0) { 18: throw new myEmptyFile($filename); 19: } 20: } catch (myFileNotExist $e) { 21: echo $e->getMessage(); 22: } catch (myEmptyFile $e) { 23: echo $e->getMessage(); 24: } 25: } 26: echo "<p>測試 abc.txt 此檔案應該不存在 <br>"; 27: checkfile("abc.txt"); 28: echo "<p>測試 empty.txt 此檔案存在, 但是是空檔案 <br>"; 29: checkfile("empty.txt"); 30: ?>
問題與討論 何謂類別? 何謂物件? 何謂建構子? 何謂繼承? 請定義一個購物車類別, 包括會員編號, 購買金額。並可以寫入及取得會員編號。購買金額可累加及取得金額。
問題與討論 一個類別如下 class Rect { var length, width ; } 宣告二個物件A, B 。A物件length為100, width為30, B物件用預設值。請將A, B二物件的資料成員及面積顯示於網頁上。