這篇文章介紹在 PHP 的物件導向程式設計(OOP)。我將示範如何用物件導向的概念編出較少的程式碼但更好的程式。祝大家好運。
物件導向程式設計的概念對每個作者都有不同的看法,我提醒一下一個物件導向語言應有的東西:
- 資料抽象化和資訊隱藏
- 繼承
-多態性
在PHP中使用類別進行封裝的方法:
class Something {
> var $ x;
function setX($v) {
// Methods start in low) words in the method name example getValueOfArea()
$this->x=$ v;
}
function getX() {
return $this-x 當然你可以用自己的辦法,但有一個標準總是好的。
PHP 中類別的資料成員使用 "var" 定義,而資料成員是沒有型別直到被賦值。一個資料成員可能是一個 integer、陣列、聯合陣列 (associative array) 或甚至物件(object). 方法在類別中定義成函數,在方法裡存取資料成員,你必須使用 $this->name 這樣的辦法,否則對方法來說是一個函數的局部變數。
使用 new 來建立一個物件
$obj = new Something;
然後使用成員函數
$obj->setX(5); ;
setX 成員函數將 5 賦給物件(而非類別)obj 中成員變數, 接著 getX 傳回值 5.
你也可以用物件引用來存取成員變數,例如:$obj-xx =6; 然而,這不一種好的物件導向程式設計的方法。我堅持你應使用成員函數來設定成員變數的值和透過成員函數來讀取成員變數。如果你認為成員變數是不可訪問的除了使用成員函數的辦法,你將成為一個好的物件導向程式設計師。但不幸的是 PHP 本身沒有辦法宣告一個變數是私有的,所以允許糟糕的程式碼存在。
在 PHP 中繼承使用 extend 來宣告。
class Another extends Something {
var $y;
lowercase then use lowercase to seperate
// words in the method name example getValueOfArea()
$this->y=$v;
return $this->y;
}
}
?>
這樣類別 "Another" 的物件擁有父類別所使用的成員變數及方法函數,加上自己
的成員變數及成員函數。如:
$obj2=new Another;
$obj2->setX(6);
$obj2->setY(7);
多重繼承不被支持,所以你不能讓一個類繼承多個類別。
在繼承類別中你可以重新定義來重定義方法,如果我們在 "Another" 重新定義 getX,那麼我們不再能存取 "Something" 中的成員函數 getX. 同樣,如果我們在繼承類別中宣告一個和父類別同名的成員變量,那麼繼承類別的變數就會隱藏父類別的同名變數。
你可以定義一個類別的建構子, 建構子是和類別同名的成員函數,在你建立類別的物件時被呼叫。
class Something {
var $x;
function Something }
function setX ($v) {
$this->x=$v;
}
🎜> }
}
?>
所以可以用以下方法建立物件:
$obj=new Something(6);
建構子自動賦值 5 給成員變數 x,而建構子和成員函數都是普通的PHP函數,而給成員變數 x所以你可以使用預設參數。
function Something($x="3",$y="5")
然後:
$obj=new Something(); // x=3 and y=
$obj =new Something(8); // x=8 and y=5
$obj=new Something(8,9); // x=8 and y=9 缺省缺節參數的定義方法及一樣,因此你不能傳一個值給 Y 但讓 X 取缺省值,實參的傳遞是從左到右,當沒有更多的實參時函數將使用缺省參數。
只有當繼承類別的建構子被調用後,繼承類別的物件才被創建,父類別的建構子沒有被調用,這是PHP不同其他物件導向語言的特點,因為建構函式調用鍊是物件導向編程的特點。如果你想呼叫基底類別的建構函數,你不得不在繼承類別的建構子中明確地呼叫它。這樣它能運作是因為繼承類別中父類別的方法全部可用。
function Another() {
$this->y=5;
$this->Something(); /🎜> $this->Something(); ///// 🎜>?>
在物件導向程式設計中一個好的機制是使用抽象類,抽象類別是一種不能實例化而是用來為繼承類別定義介面的類別。設計師常用抽象類別來強製程式設計師只能從特定的基底類別來繼承,所以就能確定新類別有所需的功能,但在PHP中沒有標準的辦法做到這一點,不過:
如果你在定義基底類別是需要這個特點,可以透過在建構函式中呼叫 "die",這樣你就可以確保它不能實例化,現在定義抽象類別的函數並在每個函數中呼叫 "die",如果在繼承類別中程式設計師不想重定義而直接呼叫基底類別的函數,將會產生一個錯誤。此外,你需要確信因為PHP沒有類型,有些物件是從基類繼承而來的繼承類別創建的,因此增加一個方法在基類來辨別類(返回 "一些標識")並驗證這一點,當你收到一個物件作為參數派上用場。 但對於一個惡棍程式沒用辦法,因為他可以在繼承類別中重定義此函數,通常這種辦法只對懶惰的程式設計師奏效。當然,最好的方法是防止程式接觸到基底類別的程式碼只提供介面。
重載在PHP中不被支援。在物件導向程式設計中你可以透過定義不同參數種類和多少來重載一個同名成員函數。 PHP是一種鬆散的型別語言,所以參數型別重載是沒有用的,同樣參數個數不同的辦法重載也不能運作。
有時候,在物件導向程式設計中重載建構子很有用,所以你能以不同的方式創建不同的物件(透過傳遞不同的參數個數)。一個小巧門可以做到這一點:
class Myclass {
function Myclass() {
$this-> $name();
//Note that $this->$name() is usually wrong but here }
function Myclass1($x) {
code;
} }
}
?>
透過這種辦法可以部分達到重載的目的。
$obj1=new Myclass(1); //Will call Myclass1
$obj2=new Myclass(1,2); //Will call Myclass2
好感覺!
多態性
多態性定義為當在運作時刻一個物件作為參數傳遞時,物件能決定呼叫那個方法的能力。例如,用一個類別定義了方法 "draw",繼承類別重定義 "draw" 的行為來畫圓或正方形,這樣你就有一個參數為 x 的函數,在函數裡可以呼叫 $x->draw() . 如果支援多態性,那麼 "draw" 方法的呼叫就取決於物件 x 的型別。多態性在PHP中很自然被支援(想想這種情況在C++編譯器中如果編譯,那一個方法被呼叫?然而你不知道物件的類型是什麼,當然現在不是這種情況)。幸好PHP支持多態性。
function niceDrawing($x) {
//Supose this is a meth >$ obj=new Circle(3,187);
$obj2=new Rectangle(4,5);
$board->niceDrawing($obj); //will callthe draw . ->niceDrawing($obj2); //will call the draw method of Rectangle.
?>
PHP 的物件導向程式設計
純對象的物件是對分子的類型PHP.P.的。 PHP是一種混合語言,你可以用物件導向或傳統結構程式設計的方法來使用它。對於大型工程,然而你可能或需要使用純粹物件導向方法來定義類,並在你的工程中只使用物件和類別。越來越大的工程透過使用物件導向的方法會獲得益處,物件導向工程非常容易維持,容易理解且重複使用。這是軟體工程的基本。使用這些概念在網站設計中是未來成功的關鍵。
PHP中的高階物件導向技術
在回顧物件導向的基本概念之後,我將介紹一些更進階的技術。
序列化
PHP並不支援持久性對象,在物件導向語言中持久性物件是一些經過應用程式多次呼叫仍然保持其狀態和功能的對象,這意味著有一種能保存對象到文件或資料庫中然後重新裝載物件。這種機制稱之為串行化。 PHP 有一個串列化函數,可以在物件中調用,而串行化函數則回傳一個字串代表這個物件。然後串行化函數保存的是成員資料而不是成員函數。
在PHP4中,如果你串列化一個物件到字串 $s, 然後刪除此對象,再反串列化物件到 $obj,你仍然可以呼叫物件的方法函數。但我不推薦這種方法,這因為 (a) 這種功能在將來不一定支援(b)這導致一種幻象,如果你保存串行化物件到磁碟並退出程式。將來重新運行此腳本時你不能反串行化此物件並希望物件的方法函數仍然有效,因為串行化出來的字串並沒有表示任何成員函數。最後,串列化保存物件的成員變數在PHP中非常有用,僅僅如此. (你可以串列化聯合陣列和陣列到磁碟裡)。
範例:
$obj=new Classfoo();
$str=serialize($obj);
// Save $str ..some months later
//Load str from disk
$obj2=unserialize($str)
?> disk
$obj2=unserialize($str)
?>
上例中,你可以恢復成員沒有函數成員根據文件。這導致 $obj2->x 是
唯一的方法來存取成員變數(因為沒有成員函數)。
這裡還有一些方法解決這個問題,但我留下給你因為它會搞髒這個乾淨的文檔。
我希望PHP將來能全面支援串列化。
使用類別來操縱已儲存的資料
PHP 和物件導向程式設計中一個比較好的地方是你很容易定義類別來操縱某些東西,並且當需要時呼叫合適的類別。假設有一個HTML文件,你需要透過選擇產品的 ID 號來選擇一個產品,你的資料保存在資料庫中,而你想顯示產品的信息,如價格等等。你有不同種類的產品,同樣的動作對不同的產品有不同的意義。例如,顯示一個聲音意味著播放它,而對其他產品來說可能是顯示一個儲存在資料庫的圖片。你可以用物件導向程式設計和PHP來達到,程式碼少但更好。
定義一個類,定義類別應該有的方法,然後透過繼承來定義每一種產品的類(SoundItem類, ViewableItem類,等等),重定義每個產品類的方法,使它們如你所需。根據你保存在資料庫中的表格的產品類型欄位來給每一種產品類型定義一個類,一個典型的產品表應有字段(id, 類型, 價格, 描述,等等)。在腳本中你從資料庫的表中取得類型信息,然後實例化對應類別的物件:
$obj=new $type();
$obj->action();
?>
這是PHP比較的特性,你可以呼叫 $obj 的顯示方法或其他方法而不用去管物件的型別。透過這種技術,當你增加一種新類型的物件時,你不需要去修改腳本。這個方法有點威力,就是定義所有物件應有的方法而不管它的類型,然後在不同的類別中以不同的方式來實現,這樣就可以在腳本中對不同的類型物件使用他們,再沒有 if,沒有兩個程式設計師在同一個文件裡,永遠快樂。你相信程式設計是這樣快樂不?維護代價小且可重複使用?
如果你帶領一組程式設計師,最好的方法是分割任務,每人可以對某種類別和物件負責。國際化可以用同樣的技術解決,讓合適的類別對應使用者所選擇的不同的語言等等。
複製和克隆
當你創建一個對象 $obj, 你可以使用 $obj2 = $obj 來拷貝一個對象,新的對像是 $obj 的一個拷貝值(不是引用有 $obj 同新的狀態。有時候你不想這樣,只想創建和 obj 同樣的新對象,調用新對象的建構函數如同你曾使用過 new 指令。這可以透過PHP的串列化和使用基底類別並且其他類別必須從基底類別繼承來達到。
進行危險的地帶
當你串行化一個對象,你得到一個有特定格式的字符串,如果你有好奇心,可能你會探尋其中的秘密,字符串中有一個東西就是類的名字,你可以解開它:
$herring = serialize($obj);
$vec = explode(":",$herring); (""", "", $vec[2]);
?>
假設你建立一個類別 "Universe" 並且讓所有類別都從 "Universe" 繼承而來,你可以在「verseUniverse」定義一個複製的方法:
class Universe {
function __clone() {
$vec=explode(":", $herring);
$nam=str_replace(""", "",$vec[2]);
🎜> }
}
//Then:
$obj=new Something();
//Something extends Universe !!
$other=$obj->__clone(); !!
$other=$obj->__clone(); !!
$other=$obj->__clone(); !!
> 你所得的是類 Something 的新物件如同使用 new 一樣,並且建構函數被呼叫等等。我不知道這對你是不是有用,這是一個很好的實踐,Universe 類別知道它的繼承類別的名字。對你來說,唯一的限制就是你的想像力! ! !
註:我使用的是PHP4, 文章裡有些東西可能不適合PHP3。
-結束-
以上就介紹了物件導向 PHP 中的物件導向程式設計:通往大型 PHP 工程的辦法,包括了物件導向方面的內容,希望對PHP教學有興趣的朋友有所幫助。