若干年前,PHP5由面向過程轉變為物件導向語言,在各個技術論壇上掀起了滔天大浪,很多人斷言PHP自取滅亡,但不久之後塵埃落定,大部分人由不支持轉向支持,PHP也由4.0時代被人戲稱為小孩的玩具,搖身一變而成為僅次於java和c的第三大語言。身處整個爭論過程,我自以為對物件導向有了完整的認識,並逐漸開始全面採用物件導向方式編程,2008年以後,甚至開始只在zend framework框架下編寫程式。
但最近數月的工作經歷讓我開始反省,我開始重新思索那個當年最著名的問題:「如果真的完全面向對象,我們何不直接使用JAVA?我們為什麼需要兩個JAVA呢?」是的,用PHP,理由之一,就是我們不一定要面對對象。一切程式設計技術和程式設計理念都只是手段,用最短的時間達成客戶需求,才是我們的目的所在,拋開這一目的而空談任何技術,都無疑是錯誤的,一個很典型的例子,開源的論壇程式中,所有PHPER人人都推崇PHPBB,而對DISUCZ的程式碼技術含量嗤之以鼻,可是,真正建論壇的時候,我們誰用PHPBB了?國內的大半論壇,都是DISCUZ的。近兩年多時間,我都拘泥於面向對象,而浪費了大量的時間,這是我犯下的一個嚴重錯誤。
所以,我決定重新梳理一下我對PHP程式設計的認識,以後在專案選型時可以選擇更合適的架構而不是唯技術是從。歡迎大家拍磚。
一、函數的作用
時至今日,任何一個非電腦專業的朋友也都該學過一門電腦語言,在國內,通常是basic,如果夠幸運,也可能是C,分支語句和循環語句是其中的必修內容,而如果函數學得不好,估計馬馬虎虎,也就過去了。就算世上沒有函數這種東西,程式一樣可以完成所有的功能(天可憐見,最近幾個月,我剛剛見識了這樣一個專案)。
那麼,我們要函數什麼用呢?無數教科書告訴我們,是為了可重複使用。是的,一個函數寫完之後,下次用到同樣功能,直接呼叫就可以了,不用再重新寫一遍了,這是函數發明的本意和基本功能。可是,如果我們預期一個功能不那麼常用,是不是就該不用函數了呢?不是的,即使是採用過程導向的程式設計方式,我們仍然要盡可能的使用函數,並儘可能的細分功能,為每個功能寫一個獨立的函數。採用函數編程,有以下幾個明顯的優點:
邏輯清晰。無論多複雜的功能,當它被細分再細分,成為多個單一功能之後,每個單一功能的邏輯都是非常簡單的,我們可以很輕鬆地根據邏輯填寫代碼而不必再為此勞神費力;
測試方便。用函數寫程序,事實上是給程序做了天然的中斷,我們能很迅速地知道,是哪段程式碼發生了錯誤。每個程式設計師心裡應該都很清楚,我們測試程式碼所花費的時間,通常兩倍甚至三倍於我們寫程式的時間。
閱讀輕鬆。當一個程式寫完一段時間之後,客戶在使用時發現問題,或是需要更改功能,程式設計師對哪怕是自己寫的程式碼,也未必就能記憶清楚,而閱讀主要由函數編寫而成的程式時,主程式基本上就是一個大綱,我們能夠順著主程式的脈絡迅速地找到對應的功能函數。
簡單復用。通常,一個函數完成時必然是經過測試的,只要當時的測試仔細一點,以後,就可以假定這個函數是正確的了,隨時根據函數說明調用就行,不必再關注其中的細節。
修改快速。有時我們也不能避免一些功能上的修改,當你的多個程式裡呼叫同一個功能函數時,只要修改這個函數,所有地方都會同時改變,而不再需要逐一修改。
因為有了以上優點,採用函數進行面向過程方式編程,是所有人公認的方法,從來都沒有見過哪個論壇有人提出質疑過。
二、程式碼註解
和很多人的習慣不同,我是喜歡大量註釋的,而且是符合phpdocument標準的註釋,這樣,當我或者同事用zend studio或netbeans之類的專業編輯當器開啟程式碼時,輸入首字母,會自動跳出我所寫的函數和方法,然後就能看到我用中文註解的函數功能、用法、參數要求和傳回格式。每個程式設計師都希望接手的程式碼註釋越多越好,但很多人自己卻很少寫註釋,我在論壇和QQ群組裡了解到了一些言論,發現這多半不是懶惰造成的,不寫註釋或少寫註釋,更多是出於對失業的恐懼和缺乏基本的自信,以至於期望別人難以接手從而保證自己的職位穩定。
三、用類別取代函數
終於說到物件導向程式設計的基本方式了,在類別裡面,我們把變數稱為屬性,把函數稱為方法,老外每提出一個新的概念就總喜歡做一些新的命名,這樣做的好處在於,當年我們提到屬性和方法時,總是顯得比那些說變數和函數的人有學問。當然,實質上,它們完全是同一回事。
為什麼要用類,照我個人的理解,最初,這多半是因為變數的作用域造成的。全域變數的安全性在C語言的入門教學中就開始提及的,不只是容易產生漏洞被駭客入侵,更多的時候,當自己寫程式碼時,也會因為全域變數的同名而產生各種預料不到的麻煩。而如果用參數傳遞每個變量,則會顯得很累贅。由於有了netbeans這樣卓越的程式設計工具,事實上,我並沒有用手工輸入這些變量,而只是看著不爽而已。明明是多數函數或至少是一組函數都會用到的變量,偏偏要反覆傳值,總是會覺得不舒服。於是,就有了類,而且,在PHP5.0之後,可以在類別裡面詳細定義屬性(變數)和方法(函數)的作用域。
同時,用類別的另一個基本好處,就是可以把函數分組。當函數足夠多的時候,會很難尋找,根據功能按類別把函數分開,那些只供其他函數調用而不需要用戶直接調用的方法,乾脆設為私有,免得同事不慎調用出錯,這樣,一個公共的函數庫就被完全分解成多個類別了。
很多時候,一個類別具備的基本功能是有普遍價值的,我們可以把一個類別從一個項目中復製到另外一個項目,而完全不用擔心出什麼差錯,這是沒有自己屬性值和作用域的函數組所無法做到的。
在這裡,需要澄清的一個問題是,很多人都誤認為把一個函數庫分為多個會加速程式運行,他們的理解是每次頁面只調用自己用到的那個函數庫或是類,文件的容量小了,速度自然快了。其實,實際情況是相反的,我們平常用電腦都知道,第一次打開一個WORD檔案時,速度可能會比較慢,而關閉後不久第二次打開,速度就會快很多,這是因為,那個WORD檔案和WORD軟體本身,都被快取到記憶體裡了。同樣道理,一個函數庫,再怎麼樣也大不到哪裡去,頁面第一次調用時被緩存,接下來再次打開自然就快了很多;同時,如果一個頁面本來包含一個函數庫夠了,如果分解後變成需要包含多個,文件尋道比加載需要花費更多的時間,所以即使是沒有緩存的情況下打開頁面,把一個函數庫分解後,也會降低程序的執行速度;另外,類的實例化也是需要一定時間的。當然,以現在的電腦硬體而言,這些速度上的損失,是完全可以忽略不計的,所以,硬體的發展,也是物件導向方式程式設計開始流行的基礎之一。
所以,在面向過程的程序中,我們還是會使用類,當然,在面向過程的程序中,只在三種情況下需要用類:
項目足夠大,大到一個函數庫會把人繞暈的時候;
我們發現自己寫的某項功能具備通用性的時候;
我們調用之前寫的類或是別人在網上發布的開源類的時候。
使用簡單的類別之後,你仍然不能宣稱你的網站是面向對象的。我剛剛在這個帖子的標題後面加了個“(上)”,也就是說,在本文接下來的篇幅當中,我們仍然只談面向過程中就可以使用到的技術,當然,它們也同樣適合於面向對象。我將在下一個貼文表達我對物件導向的理解。
四、模板
大名鼎鼎的smarty,就算沒用過,也一定都聽說過吧。最早是透過xoops認識它的,當時只做過簡單留言板的我,學習SMARTY可以說是費了九牛二虎之力。記得那時找到的最好的SMARTY網絡教程是大師兄smarty教程,好不容易搞懂了,過了一段時間,喜悅國際村里的兄弟們合夥翻譯了整個smarty文檔,但就在那時,我決定放棄smarty了,因為我堅持認為,{$x}和沒有任何區別,所謂模板,include就足夠了,為了少打幾個字母而去採用這麼大一個傢伙,是相當不值得的。嗯,這裡解釋一下我當初,哦,直到現在還有時候有用到的簡單PHP模板用法吧:
文件demo.php: 48 49 view plaincopy to clipboardprint? 50 <?php 51 $userName='张三'; 52 include_once 'templates/demo.phtml'; 53 ?> 54 <?php 55 $userName='张三'; 56 include_once 'templates/demo.phtml'; 57 ?> 58 文件demo.phtml: 59 60 view plaincopy to clipboardprint? 61 <html> 62 ...... 63 <body> 64 你好,<?php echo $userName;?> 65 </body> 66 </html> 67 <html> 68 ...... 69 <body> 70 你好,<?php echo $userName;?> 71 </body> 72 </html>
看看,啥技術也沒用,不也是一個模板嗎?有段時間每次論壇裡有討論smarty時我總要推銷一下我的想法,可惜人微言輕,一直沒什麼響應,直到前年,cakephp傳入中國,所用的模板技術和我的想法大有異曲同工之妙,不久之後,zend推出了自己的框架,也是同樣用了PHP來做天然的模板,同年,smarty不再作為php的核心子專案開發,如果大家訪問http://smarty.php.net , 就可以看到一段提示:
76
77 Smarty is no longer a subproject of the PHP project, and has subsequently moved to its own the PHP project, and has subsequently moved to its own.
79 所以,頁面和程式分開是絕對必要的,但是,以smarty為代表的模板技術則是沒有必要的,除非你做開源程式或是做自助建站,沒有辦法控制模板的安全性,否則,就完全不需要使用模板。 80 81 五、產生靜態頁VS 快取+偽靜態 82 83 剛開始用PHP20%建立的名稱選擇讓我驚嘆不已,雖然當時的版本還有很多功能上的不足,我還是花了很大的力氣去修改和學習它,並把我的修改發佈到了網上,神奇的是,剛剛google了一下"9466 slime修改版",竟然還有好些網站提供下載,2006年,我為一家企業做了個網站,網址是http://www.nbssdz.com ,這次是自己從頭寫的CMS,也同樣用到了產生靜態頁面技術。但是,現在,我已經不再使用這種技術了,joomla、phpwind、discuz和zend framework等等開源程式給了我們另一個技術演示:偽靜態。 84 85 產生靜態頁面的好處有兩個,一是提高網站訪問速度,減低伺服器負載,二是優化搜尋引擎,讓搜尋引擎收錄更多本站頁面。靜態頁面的缺點,當然就是「靜態」。聽起來好像是廢話,但是,很多動態的功能在靜態頁面上是無法實現的,例如根據使用者權限不同顯示不同內容。所以,現在開始流行偽靜態。偽靜態的作用,顧名思義,就是為動態頁面偽造靜態網址,以吸引搜尋引擎收錄,我的網站http://www.10000j.com ,由於基於zend framework編寫,所以天然具備偽靜態功能,當然,默認的網址目錄格式太深不利於收錄,我會在年後抽空進行改變,我的另一個網站作品:http://czj.kiloweb.cn 對目錄格式進行了優化,大家可以看到,鏈接格式的定制,是非常靈活的。當然,偽靜態的伺服器負荷,不但高於靜態頁面,甚至高於普通動態頁面,所以,我們必須靈活使用快取來提高網站回應速度,即便如此,在回應速度上,偽靜態仍然不佔優勢。 86 87 所以,對於功能要求不多的傳統內容發佈類,伺服器負荷過重的網站,我們仍然可以使用生成靜態頁技術,而對於有權限、點擊計數等要求並需要長期維護經常性增加功能的甚至是有獨立伺服器的網站,則應該使用偽靜態技術。畢竟部分功能時靜態頁面無法實現的,就算一些功能可以"想辦法"實現(比如透過ajax和iframe),「想辦法」所付出的時間成本,也太過高昂了。 88 89 六、ajax 90 91 ajax是一項令人振奮的技術,但91 ajax是一項不便之處在於在最近一個專案中,由於頁面採用了gb2312,而我採用的jquery框架的load()函數只支援utf8,所以我不得不使用iframe,然後我發現--嗯,這話說得有點神奇,用了那麼多年iframe,又用了近兩年的jquery,居然才發現--其實iframe也不錯,而且讓我少寫了很多程式碼。最近一年多,我用jquery做了很多讓老闆鬱悶的事情:我做了一些客戶從來沒有要求過的特效,只是因為這樣在技術上比較炫,從而浪費了大量時間,並且讓不懂jquery的美工和老闆自己無從下手修改。所以,我要說的是,ajax是很好的東西,jquery是第一流的ajax框架,但是,好東西一樣不要濫用,還是要從實際情況出發,有需求,才使用,而不是向我之前一段時間那樣,有需求要用,沒有需求創造需求也要用。 92 93 七、xml及json 9495 常在論壇混的好處在於,總是能及時知道流行技術的發展動向,比如,前年的某一天,很多人突然開始提出,用json來代替xml。我是舉雙手支持這個建議的。使用json除了提高存取速度之外,開發效率也會有大幅的提高。 json_encode()
96 、json_decode(),就這樣兩個簡單的函數,就能夠輕易地在PHP數組和json直接進行轉換,遠遠比simplexml和dom方便得多。所以,大多數時候,我們既不是做google的sitemap,也不是做rss,只是跟jquery傳一下值罷了,就用json吧,根本沒有必要用xml的。
以上是PHP程式設計方式的重新思索(上)的內容,且有更多相關內容請關注PHPcn)!