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