什麼是單一入口應用程序?
在解釋什麼是單一入口應用程序之前,我們先來看看傳統的 web 應用程序。
news.php 顯示新聞列表
news_edit.php 顯示新聞編輯頁面
這兩個頁面不但分別實現了兩個功能,還成爲了應用程序的兩個入口。
news.php 顯示新聞列表
news_edit.php 顯示新聞編輯頁面
這兩個頁面不但分別實現了兩個功能,還成爲了應用程序的兩個入口。
那什麼是入口啊?
打個比方,大家上 WC,都是男生進一個門,女生進一個門。這兩個門就是 WC 的兩個入口。
打個比方,大家上 WC,都是男生進一個門,女生進一個門。這兩個門就是 WC 的兩個入口。
呵呵,上面的例子應該很好理解吧。那稍微變換一下,單一入口的概念就很容易理解了。
現在我們是進一個公共 WC,不管男女都是從最外面的入口進入,交了錢以後才分別進兩個門。那最外面的入口就是這個 WC 的單一入口。
現在我們是進一個公共 WC,不管男女都是從最外面的入口進入,交了錢以後才分別進兩個門。那最外面的入口就是這個 WC 的單一入口。
所以單一入口的應用程序實際上就是說用一個文件處理所有的 HTTP 請求。例如不管是新聞列表功能還是新聞編輯功能,都是從瀏覽器訪問 index.php 文件。這個 index.php 文件就是這個應用程序的單一入口。
index.php 如何知道用戶是要使用哪一個功能呢?
很簡單,我們訪問 index.php 時跟上一個特定的參數就行了。例如 index.php?action=news 就是顯示新聞列表,而 index.php?action=news_edit 就是新聞編輯。
而在 index.php 裏面,僅用兩行代碼就可以實現這種效果。
上面的代碼中,第一行是從 url 中取出 action 參數。如果沒有提供 action 參數,就設置一個默認的 ‘index’ 作爲參數。
第二行代碼就是根據 $action 參數調用不同的代碼文件,從而實現單一入口對應不同功能的效果。
第二行代碼就是根據 $action 參數調用不同的代碼文件,從而實現單一入口對應不同功能的效果。
單一入口應用程序的入口文件很複雜?
有些朋友可能以爲單一入口程序的 index.php 會像麪條一樣複雜,其實是誤解。
例如我現在的應用程序入口文件只有下面幾行:
例如我現在的應用程序入口文件只有下面幾行:
足夠簡單了吧?
當然了,在 index.php 裏面寫上一長串 switch case 絕對是拙劣的實現方式。但這純粹是開發者自己的設計和實現問題,而不是單一入口應用程序這種設計思想的問題。
單一入口應用程序的設計思想
當web服務器(apache或者iis)收到一個http請求時,會解析該請求,確定要訪問哪一個文件。例如 [url]http://www.xxx.com/news.php[/url] 的解析結果就是要求web服務器解析 news.php 文件,並返回結果給瀏覽器。現在看看單一入口應用程序的 index.php 文件,就會發現 index.php 實際上根據 url 參數進行了第二次解析。
完成這個解析的程序一般稱爲 Dispatcher(中文的準確翻譯我也不知道),大概意思就是將不同的請求轉發到不同的處理程序進行處理。
在單一入口應用程序中,index.php 和 web服務器一起構成了一個 Dispatcher,根據 http 請求和 url 參數來確定請求的處理程序。
瞭解了 Dispatcher 的概念後,我們可以發現前面提到的兩行代碼實際上就是一個最簡單的 Dispatcher 實現:
誠然,對於一個安全、健壯的應用程序,Dispatcher 肯定不是上面那麼簡單。在調用實際代碼前,還會加上各種判斷、安全性檢查等。例如判斷 url 指定的功能是否可以訪問以及 url 中包含了無效的參數。
看到這裏,朋友們肯定會說:單一入口程序就多了就這樣一個 dispatcher ,和我直接做成 news.php、news_edit.php 等單個文件相比有什麼好處啊?
單一入口應用程序的優勢
單一入口應用程序的所有http請求都是通過 index.php 接收並轉發到功能代碼去的,所以我們在 index.php 裏面就能完成許多實際工作。
這裏我只拿安全性檢查爲例詳細說明一下:
由於所有的 http 請求都由 index.php 接收,所以可以進行集中的安全性檢查。如果不是單一入口,那麼開發者就必須記得在每一個文件的開始加上安全性檢查代碼(當然,安全性檢查代碼可以寫到另一個文件中,只需要include進來就可以了)。
但我想大家都是懶人,也許記性也不好,難免有忘記的時候。因此要記得在每一個文件前面都加上必要的include可不是件容易做到的事情。
由於所有的 http 請求都由 index.php 接收,所以可以進行集中的安全性檢查。如果不是單一入口,那麼開發者就必須記得在每一個文件的開始加上安全性檢查代碼(當然,安全性檢查代碼可以寫到另一個文件中,只需要include進來就可以了)。
但我想大家都是懶人,也許記性也不好,難免有忘記的時候。因此要記得在每一個文件前面都加上必要的include可不是件容易做到的事情。
與安全性檢查類似。在入口裏,我們還可以對url參數和post進行必要的檢查和特殊字符過濾、記錄日誌、訪問統計等等各種可以集中處理的任務。
“咦,搞這麼多功能,不是會把 index.php 搞得很複雜嗎?”
“不會的。只需要把各種功能寫到單獨的文件,然後在index.php裏面include進來就可以了!”
“不會的。只需要把各種功能寫到單獨的文件,然後在index.php裏面include進來就可以了!”
可以看出,由於這些工作都被集中到了 index.php 來完成,可以減輕我們維護其他功能代碼的難度。例如在10個文件中保持頭部的幾個include都一致可不是件讓人愉快的事情。
單一入口應用程序的缺點
任何事情都有兩面性,單一入口應用程序也不例外。由於所有 http 請求都是針對 index.php,所以應用程序的 url 看起來確實不那麼美觀。特別是對搜索引擎來說很不友好。
要解決這個問題,可以採用 url 重寫、PATHINFO 等方式。但我個人更推薦在前臺頁面不使用單一入口方式,而是保持多個文件入口。或者兩者混用。例如新聞列表採用單獨的 news.php 顯示,而用戶註冊、發表信息等則採用單一入口。因爲對於網站擁有者來說,新聞列表、新聞顯示頁面纔是需要搜索引擎關注的高價值目標,而用戶註冊頁面等交互性功能則根本沒有收錄的價值。
有朋友提到單一入口的應用程序會有很長一串參數,那麼我們分析一下下面這個 url:
index.php?url=news&news_id=123&page=2&sort=title
如果改爲直接訪問 news.php,也只不過省掉了 url=news 這一個參數而已。
index.php?url=news&news_id=123&page=2&sort=title
如果改爲直接訪問 news.php,也只不過省掉了 url=news 這一個參數而已。
所以認爲單一入口的應用程序 url 太複雜是沒有道理的。
如何組織單一入口應用程序的功能代碼?
單一入口應用程序最大的挑戰來自於如何合理組織各個功能的處理代碼。但只要遵循一定的步驟,也可以輕鬆的解決掉這個難題。
首先,對於應用程序的功能要做出一個合理的分解。例如後臺的新聞欄目可能包含“添加新聞”、“編輯新聞”、“刪除新聞”等多個功能。這時我們就可以將這一組邏輯上關聯的功能組合到一個功能模塊中,稱爲“新聞管理”模塊。
按照上面的方法整理完應用程序的功能,我們就會得到多個功能模塊,而每個模塊又是由多個功能組成。(實際上,即便不是單一入口應用程序,功能的整理也是必須的步驟。)
按照上面的方法整理完應用程序的功能,我們就會得到多個功能模塊,而每個模塊又是由多個功能組成。(實際上,即便不是單一入口應用程序,功能的整理也是必須的步驟。)
整理完功能後,我們就需要確定如何存放各個功能的代碼。這裏我推薦兩種方式:
1、每個功能模塊一個子目錄,目錄裏的每一個文件就是一個功能的實現代碼。
這種方式的好處是每個功能的代碼都互相隔離,非常便於多人協作。缺點是每個功能之間共享代碼和數據不那麼方便。例如新聞管理模塊中的所有功能都需要一個“取出新聞欄目記錄”的功能,那麼採用這種多個獨立文件的組織方式,“取出新聞欄目記錄”就只能寫在另一個文件中,然後由需要該功能的文件include進去。
這種方式的好處是每個功能的代碼都互相隔離,非常便於多人協作。缺點是每個功能之間共享代碼和數據不那麼方便。例如新聞管理模塊中的所有功能都需要一個“取出新聞欄目記錄”的功能,那麼採用這種多個獨立文件的組織方式,“取出新聞欄目記錄”就只能寫在另一個文件中,然後由需要該功能的文件include進去。
2、每個模塊一個文件,模塊中的每個功能寫成一個函數或者一個類方法。
好處不用多說了,非常便於共享代碼和數據。缺點就是如果幾個人同時改,容易發生衝突。不過藉助版本控制軟件和差異比較合併工具,衝突還是很容易解決的。
好處不用多說了,非常便於共享代碼和數據。缺點就是如果幾個人同時改,容易發生衝突。不過藉助版本控制軟件和差異比較合併工具,衝突還是很容易解決的。
好了,我們的功能代碼都確定存放方式了。那麼如何調用呢?
index.php 如何調用功能代碼?
調用首先就是要設計一個規則,然後讓 index.php 根據這個規則來搜索和調用功能代碼。就我自己來說,我總是使用 $_GET[’url’] 來指定要調用的功能模塊,而 $_GET[’action’] 來指定該模塊的特定功能。因此我的應用程序會使用如下的 url 地址:
index.php?url=news&action=edit
index.php?url=news&action=edit
覺得兩個參數太多了?那可以使用 index.php?func=news.edit 這樣的 url。只需要將 news.edit 拆開爲 news 和 edit 就行了。
“嘿嘿,那我故意搞一個 index.php?url=news&action=xxx,看你的應用程序還能運行?”
很顯然,這樣的 url 只會使得 index.php 無法找到需要的功能代碼,最後報告錯誤。但是這和你在瀏覽器中訪問 newsxxx.php 這個並不存在的文件有什麼本質區別呢?
很顯然,這樣的 url 只會使得 index.php 無法找到需要的功能代碼,最後報告錯誤。但是這和你在瀏覽器中訪問 newsxxx.php 這個並不存在的文件有什麼本質區別呢?
相反,我還可以讓 index.php 在發現找不到需要的功能代碼時顯示一個漂亮的出錯頁面,並提供一個返回網站首頁的連接。
在實際開發中,我傾向於將一些基本服務從應用程序中抽取出來,形成一個應用程序框架。這個框架通常會包含一個 Dispatcher、基本的數據庫訪問服務、模版引擎、常用的輔助功能等。由於有了一個框架,所以我可以更加讓 Dispatcher 更加靈活。例如可以對某些功能模塊應用權限檢查,而另一些則不檢查。
進一步瞭解單一入口應用程序
要深刻理解一個事物,自己嘗試一下是最好的辦法。
你可以選擇自己實現一個 Dispatcher 以及相應的各種規則,或者選擇一個現有的應用程序框架。但更好的方式還是首先嚐試一下現有的框架,然後再自己嘗試實現一個類似的。這樣可以在最短的時間內獲得最多的收穫。
目前絕大多數 php 應用程序框架都是單一入口的,並採用了 MVC 模式(很遺憾,由於 MVC 實在太複雜,並且和單一入口應用程序也沒有必然聯繫,所以我就不贅述了。感興趣的朋友可以 google 一下相關資料)。
我個人推薦下面的框架:
FLEA1
[url]http://trac.dualface.com/trac/flea1/[/url]
嗯,我在做廣告。因爲這個框架是我做的。但我相信這個框架將是一個非常容易上手(就算不是最容易的)框架。
全中文的代碼註釋、簡單的結構、精簡的代碼都是 FLEA1 框架的優勢。
[url]http://trac.dualface.com/trac/flea1/[/url]
嗯,我在做廣告。因爲這個框架是我做的。但我相信這個框架將是一個非常容易上手(就算不是最容易的)框架。
全中文的代碼註釋、簡單的結構、精簡的代碼都是 FLEA1 框架的優勢。
CakePHP
[url]http://www.cakephp.org/[/url]
一個 Ruby on Rails 的 PHP 仿製品。具有出色的功能,但顯然太過於複雜,而且缺乏中文資料是個很大的問題。
[url]http://www.cakephp.org/[/url]
一個 Ruby on Rails 的 PHP 仿製品。具有出色的功能,但顯然太過於複雜,而且缺乏中文資料是個很大的問題。
其他
還有 Mojavi、Phing 等許多 PHP 框架,如果你精力充沛,可以去探索一下。
還有 Mojavi、Phing 等許多 PHP 框架,如果你精力充沛,可以去探索一下。
轉自[廖宇雷的部落格]