本文針對的讀者
本文針對希望瞭解PHP中有關物件導向與面向過程兩種編程方式的讀者,包括新手和老手。假設讀者對PHP及類的使用有一定程度的熟悉。
簡介
“真正的天才具有正確評價不確定的,有風險的和矛盾的資訊的能力。--邱吉爾”
使用許多程式設計語言時,你通常只能使用物件導向或面向過程二者之一的編程方式。而在PHP中,你可以自由選擇或混用。目前絕大多數PHP程式員使用面向過程的方式,因為解析WEB頁面本身就非常“過程化”(從一個標籤到另一個標籤)。在HTML中嵌入過程處理代碼是很直接自然的作法,所以PHP程式員通常使用這種方式。
如果你是剛接觸PHP,用面向過程的風格來書寫代碼很可能是你唯一的選擇。但是如果你經常上PHP論壇和新聞群組的話,你應該會看到有關“對象”的文章。你也可能看到過如何書寫物件導向的PHP代碼的教程。或者你也可能下載過一些現成的類庫,並嘗試著去執行個體化其中的對象和使用類方法--儘管你可能沒有真正理解這些類為什麼可以工作,或者為什麼需要使用物件導向的方法來實現功能。
應該使用“物件導向”的風格還是“面向過程”的風格?雙方各有支援者。像“對象是低效的”或“對象非常棒”這樣的議論也時有耳聞。本文不嘗試輕易判定兩種方法的哪種具有絕對的優勢,而是要找出每種方法的優缺點。
以下是面向過程風格的程式碼範例:
以下是物件導向風格的程式碼範例:
myPrint(); ?>
如果你想瞭解一些“物件導向”的基本知識,請使用Google搜尋,網路上有非常多精彩的文章。
誰像這樣寫代碼?
為了理解為什麼這個論題成為論壇上口水戰的導火線,我們看一些每個陣營的比較極端的例子。我們看看“過程狂熱”和“對象狂熱”。看看他們的觀點聽起來是不是有點熟悉。
過程狂熱
過程狂熱曾在上課時被電腦教師批評,因為這種方法沒有使用更加抽象的實現方式。而支援面向過程者的觀點“它可以工作!”並不能提高其編程水平和檔次。畢業後他們可能找到一個工作,寫驅動程式,檔案系統或其它的偏向底層的編程,他們的注意力集中於速度和代碼的精鍊。
“過程狂熱”極端的例子是抵制對象,抵制抽象化。他們總在想著如何讓程式運行起來更快,而不在乎別人是否能讀懂他們的代碼。他們常常把編程當成競賽而不是團隊活動。除了PHP外,他們最喜愛的程式設計語言是C和彙編。在PHP世界中他們可能會開發PECL模組,貢獻出高效率的代碼。
對象狂熱
對象狂熱者熱衷於在任何時候使用物件導向的風格來書寫代碼。他們沒有真正考慮過用這種方式是否會影響程式的執行效率。有時候讓人覺得他們更享受抽象的設計概念而不是現實的代碼。他們通常很可能是專案管理者或文檔書寫者。
對象狂熱者指出,如果沒有抽象的設計方法我們仍然在使用0和1進行編程。他們喜歡用偽碼來描述問題。極端的例子是對象狂熱者即使知道有時候會犧牲效率仍然使用對象。 除了PHP,他們最喜歡的語言是Java和Smalltalk。在PHP世界中,他們可能會開發PEAR模組,貢獻文檔化非常好,易於維護的代碼。
不要偏激和諷刺
你知道為什麼論壇上總是充斥著各種偏見嗎?你的經驗閱曆,你對新事物的態度都可能是原因。作為程式員,我們需要時常注意這些偏見並以開放的心態去學習新事物。
你的編碼傾向?
考慮一下當你書寫PHP代碼時有什麼偏好或傾向。通常這些偏好是比較隱晦的。有時候你可能在每個項目中有著同樣的偏好。我個人傾向於“優雅”,但我不想在此定義如何才是“優雅”的代碼,那應當出現在另一篇文章裡。但是,理論化的偏好不一定適合於實際項目—相反地,他們常常是一種偏見。
理論化的傾向
• 用最少行數的代碼提供一個完整的解決方案
• 在問題層次上考慮問題
這聽起來似乎很不錯。但“程式碼數最少”如何來衡量呢?要把代碼注釋算在內嗎? 我們是否要把每一行都串起來而只用分號來區分呢?大括弧呢? 很明顯這種想法是錯誤的。
再解釋一下什麼是“問題層次”。這是否意味著在我們的方案中的每個概念都需要建立一個類?或者需要在每個獨立的檔案裡保持問題的每個部分,並建立一個複雜的檔案樹來與現實中的問題相對應?就是這樣的想法--為每個想法準備一個檔案或類!
很明顯這些概括極端化後變得可笑。但現實中存在更微妙的證明。是否常常會有程式員在團隊合作時插入一行複雜的,強大的但沒有注釋的代碼?這對於接手維護這些代碼的人來說無疑是非常令人沮喪的事。 相反地,是否你的官僚的自以為是的上一級程式員常常“橫衝直撞”般地,建立介面和類? 而那些介面和類不僅僅限制了負責實現的程式員,也限制了效率和靈活性,導致客戶要求擴充程式時手足無措。 這些都是以上各種傾向的微妙的證明。
實際傾向
一個項目開始的時候,首先要尋求實際的編碼目的和方向。這個項目的實現目標是什嗎?下面是可能是答案。
• 開發快,發布快
• 儘可能快地運行
• 易於維護,改進和擴充
• 發布一個API
第一、二個方向傾向於使用過程化的風格,而最後兩個傾向於使用物件導向的風格。
什麼時候某種方式更有效?
現在讓我們試著評價每種方式在現實中的優勢。
面向過程案例
有關PHP的面向過程化編程優勢的一個基礎性的論據是:PHP是一個解釋性的語言--這意味著,不像其它的語言一樣,它不會被編譯成一個可執行檔包,而是被解釋並馬上執行。它是一種指令碼語言並儲存於文字檔中(例外的,如果使用了Zend編譯工具)。
另一個反對在PHP4及更低版本中使用物件導向方式進行編碼的理由是:在PHP的早期版本中對象的功能並沒有經過良好設計。就像Rasmus曾說過的:“那是事後才想起要增加的功能”。這意味著在PHP4及更早的版本中,對象的效率是個問題。但PHP5出來後,這種情形會有改觀。
以下兩個最流行的PHP程式--OsCommerce 和PhpMyAdmin.主要使用面向過程的編碼方式。它們構建起來很快,運行起來也很快。兩者都很自然地採用嵌入HTML的方法。
OsCommerce
OsCommerce實際上使用了很多個物件,但絕大部分功能是通過“過程”來實現的。我曾經hack過OsCommerce,為其增添一些對於客戶非常實用的自訂功能。這個過程是挺麻煩的,因為OsCommerce中的很多過程代碼,沒有使用模板化的系統,並且設計成多語言版,所以需要花一定的時間才能上手。但是它可以工作,事實上它已經很好地運行在數目眾多的電子商務網站上了。OsCommerce同時提供了一個論壇和一個開發架構用來開發模組和外掛程式。因此,現在已經有了很多其它開發人員提供的實用的功能模組。
PhpMyAdmin
PhpMyAdmin直接使用的類只有一個:Mimer SQL Validator類,依賴於PEAR包中的Mail_Mime, Net_DIME 和 SOAP。這可能是考慮到開發的方便:利用現成的可以實現目的的代碼。除此之外,一切都是面向過程的,HTML和PHP代碼也是混雜在一起。
PhpMyAdmin是我幾乎每天都要用到的一個工具,用來對少量的資料表進行不太複雜的處理。有時我甚至鼓勵我的客戶將它當作後端的管理工具來使用(當然我會限制他們的許可權)。PhpMyAdmin的表現非常棒,也很快。有時我想在一些項目中擴充PhpMyAdmin作為後端的管理工具,利用它的一些新功能如資料查詢語句書籤可以很方便地展示給我的客戶和編輯。隨著每個新版本的推出,PhpMyAdmin越來越實用,功能越來越強大。
面向過程小結
以上兩個使用面向過程風格的程式都有非常好的文檔和代碼注釋。OsCommerce提供的開發架構可以增加維護性和擴充性。但是兩者都沒有提供API,不能擴充程式到另外的體系中。
如果你想把OsCommerce整合到一個帳單程式中,需要花費大量的時間和精力,就像擴充PhpMyAdmin成一個供客戶使用的後端管理工具。不過從它們設計的目的來看,確實在各自的領域中都表現地很出色。
物件導向案例
支援物件導向風格者的觀點都集中於擴充性和封裝。僅僅用物件導向的方式來寫代碼不會為你的代碼產生文檔,但它可以鼓勵你為之添加文檔。並且,為了易於擴充,你可能會寫一個API。 PHP5確保讓物件導向編程更加愉快。我開玩笑地將它稱為PHP中的”Java 2”版本,因為它整合了Java中的許多特性,像介面,物件導向模型,try-catch語句等。但即使在對物件導向支援不力的PHP4中,仍然出現了許多出色的物件導向應用程式。
Smarty
Smarty用來構建帶有複雜表單並基於模板的網站。最近,我寫了一個可以完全換“皮膚”的線上考試系統—可以不用改變任何底層的代碼和功能就可以將整個網站的外觀介面和風格完全改變。為了讓設計師可以易於設計新的介面,我設計了一個自訂的標籤庫作為Smarty標籤庫的擴充。可以像這樣簡單地插入:
[navigation horizontal separated by " | "]
在一個頁面的頂端有分隔開的導航。 因為Smarty已經提供了非常強大的機制來表現變數中包含的資料,這是一個映射較複雜的Smarty標籤到skin標籤的簡單過程。關於這個的更多資訊請看:http://simplequiz.peakepro.com/
由於Smarty封裝成一個類,並且它的方法都有很詳盡的文檔,使得使用模板的過程變得令人難以置信地易於擴充。同時,通過強制性地只能顯式地傳遞你要使用的變數給Smarty模板的方法,Smarty也為PHP的環境變數提供了一個保護層。這種方法有助於在Smarty模板設計師和程式員間建立安全、可靠的工作關係。
FPDF
FPDF是一個非常優秀的工具。如果你被改來改去的pdflib的API所困惑,或者不願為商業化的解決方案而交錢;或者由於共用主機的限制,無法使用擴充模組—請考慮使用這個免費的,純PHP構建的PDF產生工具。
這個類有很好的文檔,包括許多很好的例子來闡述如何在PDF中布局文本和圖片。在上面提到的同一個線上學習網站我使用FPDF來動態產生PDF檔案,使用true type字型和300dpi精度的映像。在PHP中執行個體化FPDF類並進行PDF操作並不會花費太多額外的時間,因為PDF本身就可能需要花費幾分鐘來下載。事實上,動態產生並傳送一個PDF所花的時間不比當使用一個慢速的網路連接來傳送靜態PDF檔案所花的時間多。這都是相對而言的。並且,由於FPDF是基於類的,他可以被擴充。事實上,有些類方法雖然存在但還沒有完全實現,僅作為一個架構,這可以為你在子類中建立你自己的內容(如自訂的頭尾元素)提供嚮導。
FPDF
FPDF是一個非常優秀的工具。如果你被改來改去的pdflib的API所困惑,或者不願為商業化的解決方案而交錢;或者由於共用主機的限制,無法使用擴充模組—請考慮使用這個免費的,純PHP構建的PDF產生工具。
這個類有很好的文檔,包括許多很好的例子來闡述如何在PDF中布局文本和圖片。在上面提到的同一個線上學習網站我使用FPDF來動態產生PDF檔案,使用true type字型和300dpi精度的映像。在PHP中執行個體化FPDF類並進行PDF操作並不會花費太多額外的時間,因為PDF本身就可能需要花費幾分鐘來下載。事實上,動態產生並傳送一個PDF所花的時間不比當使用一個慢速的網路連接來傳送靜態PDF檔案所花的時間多。這都是相對而言的。並且,由於FPDF是基於類的,他可以被擴充。事實上,有些類方法雖然存在但還沒有完全實現,僅作為一個架構,這可以為你在子類中建立你自己的內容(如自訂的頭尾元素)提供嚮導。
物件導向小結
Smarty和FPDF都提供了帶有良好文檔的API來擴充主類。這說明了在類的內部組織方法和資料的必要性--有時同樣的功能可以用函數和全域變數來完成,但這樣不易於擴充。並且,使用對象對跟蹤和保持PDF或HTML文檔的風格非常有協助,你可以將同樣的資料用不同的格式來發布。Smarty和FPDF都是使用對象來建立靈活實用的類庫的極好的例子。
為什麼兩種方式都是必需的?
回到我們充滿熱情的程式員身上,我們開始讚美他們:
• 我們欣賞Smarty和FPDF的實用性和擴充性
• 我們欣賞osCommerce和phpMyAdmin的運行速度和良好表現
這種欣賞還包括對PHP的一些基礎開發。PECL和PEAR都收到了很多讚揚和批評。我想這兩個項目為闡明面向過程和物件導向編程的區別提供了很好的例子。
PECl提供了PHP的擴充庫,用C和面向過程的方式開發,注重速度和簡潔精鍊。通常,這些都是從已經存在的LGPL軟體中移植而來,其中許多有趣的特性已經加入PHP。畢竟,PHP是用C寫的。
PEAR則貢獻了很多有趣的類如建立Excel表或改變DNS記錄等。使用PEAR類庫可以為你節約大量時間,甚至可以讓你在不怎麼熟悉PHP的情況進行開發—“我不理解但它能用!”。
總結
希望本文能加深你對兩種編程方式的理解,並且更重要地—鼓勵你在更具體的細節上進行探索。我希望你會有自己的想法,並在實際開發中檢驗你的項目開發傾向,總結出更多實際的案例,並不嗇寫些針對本文的評論。
總之,每種方式都有其優勢的一面,糾纏於爭論不如離開去寫些實際的代碼!
關於作者
Robert Peake得到詩歌專業學位之前,在伯克利教授電腦課程。最近辭去IT經理的職務,考慮將更多時間花在家庭和PHP上。他和妻子Valerie居住於洛杉磯。你可以通過電子郵件與他聯絡:robert at peakepro.com
關於譯者
Haohappy,《PHP&MORE》編輯,在Phpe.net上有多篇翻譯作品,內容主要涉及PHP5和OOP。