ThinkPHP開發指南-------基本概念之單一入口

單一入口應用程序的解釋? php

咱們先來看看傳統的 web開發的 應用。
有如下兩個php文件
news.php 顯示新聞列表
news_edit.php 顯示新聞編輯頁面
這兩個頁面不但分別實現了兩個功能,還成爲了應用程序的兩個入口。 web

到底什麼纔是入口呢?
打個比方,你們上 WC,都是男生進一個門,女生進一個門。這兩個門就是 WC 的兩個入口。 數據庫

呵呵,上面的例子應該很好理解吧。那稍微變換一下,單一入口的概念就很容易理解了。
如今咱們是進一個公共 WC,無論男女都是從最外面的入口進入,交了錢之後才分別進兩個門。那最外面的入口就是這個 WC 的單一入口。 apache

因此單一入口的應用程序實際上就是說用一個文件處理全部的 HTTP 請求。例如不論是新聞列表功能仍是新聞編輯功能,都是從瀏覽器訪問 index.php 文件。這個 index.php 文件就是這個應用程序的單一入口。 瀏覽器

index.php 如何知道用戶是要使用哪個功能呢? 安全

很簡單,咱們訪問 index.php 時跟上一個特定的參數就好了。例如 index.php?action=news 就是顯示新聞列表,而 index.php?action=news_edit 就是新聞編輯。 服務器

而在 index.php 裏面,僅用兩行代碼就能夠實現這種效果。
<?php
$action = $_GET['action'] == '' ? 'index' : $_GET['action'];
include('files/' . $action . '.php');
?> 框架

上面的代碼中,第一行是從 url 中取出 action 參數。若是沒有提供 action 參數,就設置一個默認的 'index' 做爲參數。
第二行代碼就是根據 $action 參數調用不一樣的代碼文件,從而實現單一入口對應不一樣功能的效果。 函數

單一入口應用程序的入口文件很複雜? 工具

有些朋友可能覺得單一入口程序的 index.php 會像麪條同樣複雜,實際上是誤解。
例如我如今的應用程序入口文件只有下面幾行:
<?php
define('APP',      realpath('../libs/website'));
define('LANG',     'gb2312');
define('DEBUG',    1);

require('../libs/flea1/basic.php');
run();
?>
足夠簡單了吧?

固然了,在 index.php 裏面寫上一長串 switch case 絕對是拙劣的實現方式。但這純粹是開發者本身的設計和實現問題,而不是單一入口應用程序這種設計思想的問題。

補充說明: 這裏提到 switch case 並非說用了 switch 就表明「落後」、「土氣」等。只是說在 index.php 這個入口程序裏面寫上一堆 switch case 不利於程序的修改和維護,因此是一種很差的用法。

單一入口應用程序的設計思想

當web服務器(apache或者iis)收到一個http請求時,會解析該請求,肯定要訪問哪個文件。例如 http://www.xxx.com/news.php 的解析結果就是要求web服務器解析 news.php 文件,並返回結果給瀏覽器。如今看看單一入口應用程序的 index.php 文件,就會發現 index.php 實際上根據 url 參數進行了第二次解析。

完成這個解析的程序通常稱爲 Dispatcher(中文的準確翻譯我也不知道),大概意思就是將不一樣的請求轉發到不一樣的處理程序進行處理。

在單一入口應用程序中,index.php 和 web服務器一塊兒構成了一個 Dispatcher,根據 http 請求和 url 參數來肯定請求的處理程序。

瞭解了 Dispatcher 的概念後,咱們能夠發現前面提到的兩行代碼實際上就是一個最簡單的 Dispatcher 實現:
<?php
$action = $_GET['action'] == '' ? 'index' : $_GET['action'];
include('files/' . $action . '.php');
?>

誠然,對於一個安全、健壯的應用程序,Dispatcher 確定不是上面那麼簡單。在調用實際代碼前,還會加上各類判斷、安全性檢查等。例如判斷 url 指定的功能是否能夠訪問以及 url 中包含了無效的參數。

看到這裏,朋友們確定會說:單一入口程序就多了就這樣一個 dispatcher ,和我直接作成 news.php、news_edit.php 等單個文件相比有什麼好處啊?

單一入口應用程序的優點

單一入口應用程序的全部http請求都是經過 index.php 接收並轉發到功能代碼去的,因此咱們在 index.php 裏面就能完成許多實際工做。

這裏我只拿安全性檢查爲例詳細說明一下:
因爲全部的 http 請求都由 index.php 接收,因此能夠進行集中的安全性檢查。若是不是單一入口,那麼開發者就必須記得在每個文件的開始加上安全性檢查代碼(固然,安全性檢查代碼能夠寫到另外一個文件中,只須要include進來就能夠了)。
但我想你們都是懶人,也許記性也很差,不免有忘記的時候。所以要記得在每個文件前面都加上必要的include可不是件容易作到的事情。

與安全性檢查相似。在入口裏,咱們還能夠對url參數和post進行必要的檢查和特殊字符過濾、記錄日誌、訪問統計等等各類能夠集中處理的任務。

「咦,搞這麼多功能,不是會把 index.php 搞得很複雜嗎?」
「不會的。只須要把各類功能寫到單獨的文件,而後在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 這一個參數而已。

因此認爲單一入口的應用程序 url 太複雜是沒有道理的。

如何組織單一入口應用程序的功能代碼?

單一入口應用程序最大的挑戰來自於如何合理組織各個功能的處理代碼。但只要遵循必定的步驟,也能夠輕鬆的解決掉這個難題。

首先,對於應用程序的功能要作出一個合理的分解。例如後臺的新聞欄目可能包含「添加新聞」、「編輯新聞」、「刪除新聞」等多個功能。這時咱們就能夠將這一組邏輯上關聯的功能組合到一個功能模塊中,稱爲「新聞管理」模塊。
按照上面的方法整理完應用程序的功能,咱們就會獲得多個功能模塊,而每一個模塊又是由多個功能組成。(實際上,即使不是單一入口應用程序,功能的整理也是必須的步驟。)

整理完功能後,咱們就須要肯定如何存放各個功能的代碼。這裏我推薦兩種方式:

一、每一個功能模塊一個子目錄,目錄裏的每個文件就是一個功能的實現代碼。
這種方式的好處是每一個功能的代碼都互相隔離,很是便於多人協做。缺點是每一個功能之間共享代碼和數據不那麼方便。例如新聞管理模塊中的全部功能都須要一個 「取出新聞欄目記錄」的功能,那麼採用這種多個獨立文件的組織方式,「取出新聞欄目記錄」就只能寫在另外一個文件中,而後由須要該功能的文件include 進去。

二、每一個模塊一個文件,模塊中的每一個功能寫成一個函數或者一個類方法。
好處不用多說了,很是便於共享代碼和數據。缺點就是若是幾我的同時改,容易發生衝突。不過藉助版本控制軟件和差別比較合併工具,衝突仍是很容易解決的。

好了,咱們的功能代碼都肯定存放方式了。那麼如何調用呢?

index.php 如何調用功能代碼?

調用首先就是要設計一個規則,而後讓 index.php 根據這個規則來搜索和調用功能代碼。就我本身來講,我老是使用 $_GET['url'] 來指定要調用的功能模塊,而 $_GET['action'] 來指定該模塊的特定功能。所以個人應用程序會使用以下的 url 地址:
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 這個並不存在的文件有什麼本質區別呢?

相反,我還可讓 index.php 在發現找不到須要的功能代碼時顯示一個漂亮的出錯頁面,並提供一個返回網站首頁的鏈接。

在實際開發中,我傾向於將一些基本服務從應用程序中抽取出來,造成一個應用程序框架。這個框架一般會包含一個 Dispatcher、基本的數據庫訪問服務、模版引擎、經常使用的輔助功能等。因爲有了一個框架,因此我能夠更加讓 Dispatcher 更加靈活。例如能夠對某些功能模塊應用權限檢查,而另外一些則不檢查。

進一步瞭解單一入口應用程序

要深入理解一個事物,本身嘗試一下是最好的辦法。

你能夠選擇本身實現一個 Dispatcher 以及相應的各類規則,或者選擇一個現有的應用程序框架。但更好的方式仍是首先嚐試一下現有的框架,而後再本身嘗試實現一個相似的。這樣能夠在最短的時間內得到最多的收穫。

目前絕大多數 php 應用程序框架都是單一入口的,並採用了 MVC 模式(很遺憾,因爲 MVC 實在太複雜,而且和單一入口應用程序也沒有必然聯繫。感興趣的朋友能夠 google 一下相關資料)。

相關文章
相關標籤/搜索