這篇文章介紹在PHP的面向對象編程(OOP)。我將演示如何用面向對象的概念編出較少的代碼但更好的程序。祝大家好運。
構造函數自動賦值 5 給成員變量 x, 構造函數和成員函數都是普通的PHP函數,所以你可以使用缺省參數。
然后:
缺省參數的定義方法和 C++ 一樣,因此你不能傳一個值給 Y 但讓 X 取缺省值,實參的傳遞是從左到右,當沒有更多的實參時函數將使用缺省參數。 只有當繼承類的構造函數被調用后,繼承類的對象才被創建,父類的構造函數沒有被調用,這是PHP不同其他面向對象語言的特點,因為構造函數調用鏈是面向對象編程的特點。如果你想調用基類的構造函數,你不得不在繼承類的構造函數中顯式調用它。這樣它能工作是因為在繼承類中父類的方法全部可用。
在面向對象編程中一種好的機制是使用抽象類,抽象類是一種不能實例化而是用來給繼承類定義界面的類。設計師經常使用抽象類來強制程序員只能從特定的基類來繼承,所以就能確定新類有所需的功能,但在PHP中沒有標準的辦法做到這一點,不過: 如果你在定義基類是需要這個特點,可以通過在構造函數中調用 "die",這樣你就可以確保它不能實例化,現在定義抽象類的函數并在每個函數中調用 "die",如果在繼承類中程序員不想重定義而直接調用基類的函數,將會產生一個錯誤。 此外,你需要確信因為PHP沒有類型,有些對象是從基類繼承而來的繼承類創建的,因此增加一個方法在基類來辨別類(返回 "一些標識")并驗證這一點,當你收到一個對象作為參數派上用場。 但對于一個惡棍程序沒用辦法,因為他可以在繼承類中重定義此函數,通常這種辦法只對懶惰的程序員奏效。當然,最好的辦法是防止程序接觸到基類的代碼只提供界面。 重載在PHP中不被支持。在面向對象編程中你可以通過定義不同參數種類和多少來重載一個同名成員函數。PHP是一種松散的類型語言,所以參數類型重載是沒有用的,同樣參數個數不同的辦法重載也不能工作。 有時候,在面向對象編程中重載構造函數很有用,所以你能以不同的方式創建不同的對象(通過傳遞不同的參數個數)。一個小巧門可以做到這一點:
通過這種辦法可以部分達到重載的目的。
[page_break] 多態性 多態性被定義為當在運行時刻一個對象作為參數傳遞時,對象能決定調用那個方法的能力。例如,用一個類定義了方法 "draw",繼承類重定義 "draw" 的行為來畫圓或正方形,這樣你就有一個參數為 x 的函數,在函數里可以調用$x->draw(). 如果支持多態性,那么 "draw" 方法的調用就取決于對象 x 的類型。多態性在PHP中很自然被支持(想一想這種情況在C++編譯器中如果編譯,那一個方法被調用?然而你不知道對象的類型是什么,當然現在不是這種情況)。 幸好PHP支持多態性。
PHP的面向對象編程 純對象論者認為PHP不是真正的面向對象語言,這是對的。PHP是一種混合語言,你可以用面向對象或傳統結構編程的方法來使用它。對于大型工程,然而你可能或需要使用純面向對象方法來定義類,并在你的工程中只使用對象和類。越來越大的工程通過使用面向對象的方法會獲得益處,面向對象工程非常容易維持,容易理解并且重用。這是軟件工程的基本。使用這些概念在網站設計中是未來成功的關鍵。 PHP中的高級面向對象技術 在回顧面向對象的基本概念之后,我將介紹一些更高級的技術。 串行化 PHP并不支持持久性對象,在面向對象語言中持久性對象是一些經過應用程序多次調用仍然保持其狀態和功能的對象,這意味著有一種能保存對象到文件或數據庫中然后重新裝載對象。這種機制稱之為串行化。PHP 有一個串行化函數,可以在對象中調用,串行化函數返回一個字符串代表這個對象。然后串行化函數保存的是成員數據而不是成員函數。 在PHP4中,如果你串行化一個對象到字符串 $s, 然后刪除此對象,再反串行化對象到 $obj, 你仍然可以調用對象的方法函數。但我不推薦這種方法,這因為(a)這種功能在將來不一定支持(b)這導致一種幻象,如果你保存串行化對象到磁盤并退出程序。將來重新運行此腳本時你不能反串行化此對象并希望對象的方法函數仍有效,因為串行化出來的字符串并沒有表示任何成員函數。最后,串行化保存對象的成員變量在PHP中非常有用,僅僅如此. (你可以串行化聯合數組和數組到磁盤里)。 例子:
上例中,你可以恢復成員變量而沒有成員函數(根據文檔)。這導致 $obj2->x 是唯一的方法來存取成員變量(因為沒有成員函數)。 這里還有一些方法解決這個問題,但我留下給你因為它會搞臟這個干凈的文檔。 我希望PHP將來能全面支持串行化。 使用類來操縱保存的數據 PHP和面向對象編程中一個比較好的地方是你很容易定義類來操縱某些東西,并且當需要時調用合適的類。假設有一個HTML文件,你需要通過選擇產品的ID號來選擇一個產品,你的數據保存在數據庫中,而你想顯示產品的信息,如價格等等。你有不同種類的產品,同樣的動作對不同的產品有不同的含義。 例如,顯示一個聲音意味著播放它,而對其他產品來說可能是顯示一個存儲在數據庫的圖片。你可以用面向對象編程和PHP來達到,代碼少但更好。 [page_break] 定義一個類,定義類應該有的方法,然后通過繼承來定義每一種產品的類(SoundItem類, ViewableItem類,等等),重定義每個產品類的方法,使它們如你所需。根據你保存在數據庫中的表的產品類型字段來給每一種產品類型定義一個類,一個典型的產品表應有字段(id, 類型, 價格, 描述,等等)。 在腳本中你從數據庫的表中獲取類型信息,然后實例化相應類的對象:
這是PHP比較的特性,你可以調用 $obj 的顯示方法或其他方法而不用去管對象的類型。通過這種技術,當你增加一種新類型的對象時,你不需要去修改腳本。這個方法有點威力,就是定義所有對象應有的方法而不管它的類型,然后在不同的類中以不同的方式來實現,這樣就可以在腳本中對不同的類型對象使用他們,再沒有 if, 沒有兩個程序員在同一個文件里,永遠快樂。你相信編程是這樣快樂不?維護代價小并且可重用? 如果你帶領一組程序員,最好的方法是劃分任務,每人可以對某種類和對象負責。國際化可以用同樣的技術解決,使合適的類對應使用者選擇的不同的語言等等。 復制和克隆 當你創建一個對象 $obj, 你可以使用 $obj2 = $obj 來拷貝一個對象,新的對象是 $obj 的一個拷貝(不是引用),所以在賦值完新對象有 $obj 同新的狀態。有時候你不想這樣,只想創建和 obj 同樣的新對象,調用新對象的構造函數如同你曾使用過 new 命令。這可以通過PHP的串行化和使用基類并且其他類必須從基類繼承來達到。 進行危險的地帶 當你串行化一個對象,你得到一個有特定格式的字符串,如果你有好奇心,可能你會探尋其中的秘密,字符串中有一個東西就是類的名字,你可以解開它:
假設你創建一個類 "Universe" 并且使所有類都從 "Universe" 繼承而來,你可以在 "Universe" 定義一個克隆的方法:
你所得的是類 Something 的新對象如同使用 new 一樣,并且構造函數被調用等等。我不知道這對你是不是有用,這是一個很好的實踐,Universe 類知道它的繼承類的名字。對你來說,唯一的限制是你的想象力!!! 注意:我使用的是PHP4, 文章里有些東西可能不適合PHP3。 |
溫馨提示:喜歡本站的話,請收藏一下本站!