簡介 “真正的天才具有正確評價不確定的,有風險的和矛盾的信息的能力。--邱吉爾” 使用許多編程語言時,你通常只能使用面向對象或面向過程二者之一的編程方式。而在PHP中,你可以自由選擇或混用。目前絕大多數PHP程序員使用面向過程的方式,因為解析WEB頁面本身就非常“過程化”(從一個標簽到另一個標簽)。在Html中嵌入過程處理代碼是很直接自然的作法,所以PHP程序員通常使用這種方式。 如果你是剛接觸PHP,用面向過程的風格來書寫代碼很可能是你唯一的選擇。但是如果你經常上PHP論壇和新聞組的話,你應該會看到有關“對象”的文章。你也可能看到過如何書寫面向對象的PHP代碼的教程。或者你也可能下載過一些現成的類庫,並嘗試著去實例化其中的對象和使用類方法--盡管你可能沒有真正理解這些類為什麼可以工作,或者為什麼需要使用面向對象的方法來實現功能。 應該使用“面向對象”的風格還是“面向過程”的風格?雙方各有支持者。像“對象是低效的”或“對象非常棒”這樣的議論也時有耳聞。本文不嘗試輕易判定兩種方法的哪種具有絕對的優勢,而是要找出每種方法的優缺點。 以下是面向過程風格的代碼示例: <?php print "Hello, world."; ?> 以下是面向對象風格的代碼示例: <?php class helloWorld { function myPrint() { print "Hello, world."; } } $myHelloWorld = new helloWorld(); $myHelloWorld->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的情況進行開發—“我不理解但它能用!”。