如何自己寫一個PHP架構
[size=small][color=darkred]在PHP的論壇中總是聽到有人對PHP的OOP支援說三道四的,說這有缺陷,那裡不足,但是都拿不出實際的例子。原來說過要和大家說說這事,但是一直很忙,現在算是抽了些時間了,所以把我剛剛做過的一個項目的架構拿出來和大家探討一下。這個項目99%的代碼是用oop方式編寫的,感覺PHP對於OOP支援非常好,不是一般的好,是非常的好。有由於項目本身是一個商業項目所以原始碼不好公布出來,但是基本架構還是可以說一說的,而且經過簡化的例子更容易理解一些。如果你對PHP中的OOP還不太瞭解,還是就此打住吧,先去看看手冊,或者基礎讀物再來看也不遲,反正這個是貼子沒有長腿也跑不了。
長話短說,立刻開始吧。我這裡會用到一個簡單的例子,只有一個半的功能。一個是向瀏覽器發送一句"Hello, I can say OOP in PHP world!",另外半個功能是從資料庫中進行一個查詢然後輸出到瀏覽器,說它是半個功能是因為只是作為一個例子講講沒有實際的資料庫操作。
首先從我的第一個檔案index.php 開始介紹吧。我的index.php檔案是這樣的:
run();?>
這個就是全部了,雖然只有4行,但是如果用OOP的方式寫這個應該就夠了吧。
有一點經驗的哥們會發現這裡只用到了一個Application 對象,那麼一定很想知道這個對象究竟長什麼樣呢?我們繼續看看class.Application.php 這個檔案的內部。從以上的代碼中我們知道她應該至少包含兩個方法——Application()和run()。所以大體上應該長成這樣:
現在就算知道Application 是什麼樣,它好像也沒有辦法完成我們預先設定的功能呀? 所以還要介紹一下如何運行這個程式,在我的結構中所有的頁面都是通過index.php和一個action參數進行訪問的例如第一個功能應該這樣訪問 index.php?action=HelloPage,而第二個功能則是通過index.php?action=DatabasePage進行訪問。這樣的結構大家也許並不陌生吧。所以index.php 頁面應當知道傳進來的 action 參數是什麼,也就是說Application對象應當知道 這個action 參數是什麼。所以我們需要給Application增加一個方法 getAction()來獲得action參數。既然知道action,知道了要做什麼,那麼方法 run()也就有知道如何去run了。
同時我還可以把(完成功能的)每一個頁面作為一個對象來看待,所以我應該至少還需要兩個類
class HelloPage 和
class DatabasePage
由於這兩個對象最終都是向瀏覽器發送頁面所以把他們共同的部分提出來作為他們的父類
class Page
以下是三個類檔案的內容
class.Page.php
其中這個show方法應該是所有頁面對象都具有的方法,只是在實現上有所不同。
class.HelloPage.php
;
class.DatabasePage.php
;
同時我們還遵守這樣的一條規則:action的值和調用的頁面類的名稱保持一致,例如當action=HelloPage的時候程式就知道需要初始化一個HelloPage的對象,有了這樣的規則和以上的幾個檔案我們就可以將 Application 類改進成這樣。
;getAction();include_once ("class.".$pageClass.".php");$page = & new $pageClass();$page->;show();}}?>
為什麼getAction()空著?因為它太簡單了,你自己可以輕鬆地把它寫出來呀。
看到這裡,如果你還不太明白,不用急,可以停下來重新再看一遍。
如果全明白了,我們就繼續前進。我們還有半個任務沒有完成,所以我們需要改進我們的Application和頁面類,讓它完成資料庫操作功能。
進行資料庫操作之前首先應當得到一個正確的資料庫連接,如果讓每個需要資料庫連接的頁面類去做這樣的工作實在是一件非常費時費力的工作,不容易維護管理而且也破壞了oop的設計初衷,進行資料庫操作的頁面類例如 DatabasePage 只應當完成它份內工作即獲得資料。 仔細看看我們的設計不難發現建立資料庫連接的工作交給 Application 來做最合適不過了, 所以給Application 增加一個新的成員 $db 並且在初始化的時候將建立的資料庫連接賦值給它。
;db = & new Database(DB_HOST,DB_NAME,DB_LOGIN,DB_PASS);//$db 現在是一個資料庫物件了}function getAction(){return $_GET['action']; //簡單的實現 getAction;}funciton & getDatabase(){return $this->;db;}function run(){$pageClass = $this->;getAction();include_once ("class.".$pageClass.".php");$page = & new $pageClass($this); //這裡是唯一做了手腳的地方,將這個Application對象傳給頁面對象。$page->;show();}}?>
你現在不用太關心這個 Database對象從何而來如何?,知道它是一個含有資料庫連接的對象就可以了,如果用過phplib, ADODB,或者Pear庫的就很容易理解。
這個語句:
$this->;db = & new Database(DB_HOST,DB_NAME,DB_LOGIN,DB_PASS);
就是建立一個資料庫連接而已。
至於DB_HOST,DB_NAME,DB_LOGIN,DB_PASS 這些都是常量我們在config.php中已經預先設定。
由於資料庫操作頁面 DatabasePage 需要進行資料庫連接所以它也需要一個變數 $db 來儲存資料庫物件,所以我們需要把DatabasePage改進成這樣:
class.DatabasePage.php
;db = $app->;getDatabase();//獲得 Application 中的資料庫物件。}function show(){$sql = 'SELECT * FROM sale_orders';//簡單的一個 SQL 例子。$results = $this->;db->;query($sql);//query 是 Database對象的一個公用的方法,通過它向資料庫提交SQL查詢。...;//做一些操作把得到的結果顯示出來。}}?>
好了,一個半的功能算是完成了,PHP對於OOP支援得也很漂亮吧,結構清晰,維護方便,至於效率嘛,我可沒看出來有什麼損失,如果你有興趣可以自己測試一下。用這樣的架構可以輕鬆應對各種需求的變化:增加各種許可權控制,分離資料庫層,商業邏輯,和表象層,增加遠程調用介面統統不成問題,只是這裡實在寫不完這麼多的東西。真不知道誰還會有理由說PHP 中OOP 很爛呢?
另外,需要提醒大家的是傳遞對象和賦值的時候要使用 & 符號這樣可以保證每次引用的是同一個對象。[/color][/size]