ThinkPHP框架設(shè)計(jì)及擴(kuò)展詳解
ThinkPHP框架是國(guó)內(nèi)知名度很高應(yīng)用很廣泛的php框架,我們從一些簡(jiǎn)單的開(kāi)發(fā)示例中來(lái)深入了解一下這個(gè)框架給我們帶來(lái)的開(kāi)發(fā)便捷性,以及游刃有余的擴(kuò)展設(shè)計(jì)。同時(shí)也從源碼分析的角度看看框架的一些不足,盡量做全面客觀的評(píng)價(jià)。這里假設(shè)大家已經(jīng)使用過(guò)ThinkPHP框架,基本使用方法請(qǐng)參考官方文檔。
一、框架分層及url路由
框架的安裝非常簡(jiǎn)單,下載后放入web服務(wù)器的目錄即可,但是建議大家不要用默認(rèn)的入口文件位置,而是放入單獨(dú)的目錄,便于保護(hù)代碼和數(shù)據(jù)。例如我的入口文件和web服務(wù)器配置目錄在web目錄(外層框架里的index.php沒(méi)有刪除但是沒(méi)有使用):
同大多數(shù)MVC框架一樣,我們只需要按框架的目錄結(jié)構(gòu),擴(kuò)展自己的Controller和View,一些頁(yè)面就開(kāi)發(fā)完成了。ThinkPHP提供Module、Controller、Action三層結(jié)構(gòu)來(lái)組織自己的url(3.1版本叫分組、Action和method,3.2更加國(guó)際范),目錄結(jié)構(gòu)如下:
這里強(qiáng)烈建議大家:
1、業(yè)務(wù)單獨(dú)分層,不用放在Controller和Model里,例如我這里通過(guò)擴(kuò)展函數(shù)庫(kù)Application/Common/Common/function.php強(qiáng)制定義業(yè)務(wù)層名稱為Service:
function service($name)
{
return D($name, 'Service');
}
好處是復(fù)用性好,假如將來(lái)要開(kāi)發(fā)wap頁(yè)面,寫了不同的Controller,就可以復(fù)用service,假如以后的數(shù)據(jù)存儲(chǔ)變了,比如把數(shù)據(jù)庫(kù)從mysql遷移到mongodb之類,那修改Model就可以,service還是不需要任何修改。
2、基礎(chǔ)模塊和業(yè)務(wù)模塊分開(kāi),不要相互引用?;A(chǔ)模塊(例如用戶基本信息)只提供數(shù)據(jù)接口沒(méi)有Controller和View。
三層目錄已經(jīng)可以應(yīng)對(duì)一般的web應(yīng)用,更加復(fù)雜的web應(yīng)用我們可以定義不同的入口文件加載不同的Application來(lái)解決。更更復(fù)雜的應(yīng)用?門戶和超大規(guī)模網(wǎng)站么,那就不是一個(gè)php框架能解決所有問(wèn)題的了,需要自己的中間件和定制框架。
ThinkPHP的支持4種url訪問(wèn)模式,分別是:
1、普通模式,傳統(tǒng)url模式,所有參數(shù)分開(kāi),例如
http://localhost/tp/index.php?m=Ucai&c=User&a=index¶=xxx
路由參數(shù):m參數(shù)表示模塊,c表示控制器,a表示訪問(wèn)方法
2、兼容模式
http://localhost/tp/index.php?s=/Ucai/User/index/para/xxx
路由參數(shù)通過(guò)s參數(shù)組裝,當(dāng)然數(shù)據(jù)參數(shù)也可以不必放在s參數(shù)里
3、pathinfo模式
http://localhost/tp/index.php/Ucai/User/index/para/xxx
這種模式把入口文件和真實(shí)腳本放在一起,含義明確,也便于SEO
4、rewrite模式
http://localhost/tp/Ucai/User/index/para/xxx
這種模式通過(guò)web服務(wù)器的rewrite配置隱藏入口文件,顯得更加友好
其中pathinfo和rewrite模式需要web服務(wù)器支持。ThinkPHP有個(gè)配置需要設(shè)置為哪種模式,其實(shí)是用在U方法里生成url鏈接的時(shí)候用到的,訪問(wèn)的時(shí)候只要web服務(wù)器支持用哪種方式都可以。
也建議ThinkPHP其實(shí)不需要配置,而是記住用戶訪問(wèn)的方式,只要第一個(gè)訪問(wèn)用的是哪種模式,以后生成的url都用這種方式生成,因?yàn)橛脩舳家呀?jīng)訪問(wèn)到了就不存在支不支持的問(wèn)題了。
如果正常的url不能達(dá)到我們的要求,還可以通過(guò)配置路由進(jìn)一步優(yōu)化url,例如我們想把url配置的更加簡(jiǎn)單
http://localhost/tp/Ucai/login/xxx
我們只需要在模塊配置文件中添加如下的路由配置即可,如果用正則表達(dá)式則可以更加簡(jiǎn)化
'URL_ROUTE_RULES' => array(
'login/:para' => 'Ucai/User/index',
'login' => 'Ucai/User/index',
),
到這里我們可以看到,ThinkPHP框架支持的層次結(jié)構(gòu)和url配置非常豐富,能滿足各種不同的需求。當(dāng)然我們建議大家不要濫用路由配置,適當(dāng)少量的配置能帶來(lái)更好的seo效果,但是大量的配置會(huì)給項(xiàng)目的維護(hù)和修改帶來(lái)困難。
二、ThinkPHP擴(kuò)展
ThinkPHP本身含有豐富的組件和驅(qū)動(dòng),我們以數(shù)據(jù)庫(kù)驅(qū)動(dòng)擴(kuò)展和行為擴(kuò)展為例來(lái)了解一下ThinkPHP的擴(kuò)展設(shè)計(jì)。
三、數(shù)據(jù)庫(kù)驅(qū)動(dòng)擴(kuò)展
雖然ThinkPHP提供了眾多的數(shù)據(jù)庫(kù)驅(qū)動(dòng),但是也并不能滿足所有的需求。例如我們的數(shù)據(jù)很可能不是通過(guò)直接訪問(wèn)數(shù)據(jù)庫(kù)去實(shí)現(xiàn),而是通過(guò)一些中間件(例如C程序)進(jìn)行轉(zhuǎn)發(fā),從而獲得更好的性能,這時(shí)就需要擴(kuò)展數(shù)據(jù)庫(kù)驅(qū)動(dòng)來(lái)支持。
擴(kuò)展非常簡(jiǎn)單,在DB/Driver目錄下新建自己的驅(qū)動(dòng),例如Custom.php,然后實(shí)現(xiàn)request和execute方法擴(kuò)展就算完成了,然后再配置文件里配置DB_TYPE='custom',就可以使用了。這里的request表示查詢,execute表示更改數(shù)據(jù),所有其他操作都會(huì)在Model里進(jìn)行解析,包裝成sql語(yǔ)句調(diào)用這兩個(gè)方法執(zhí)行。
例如我所實(shí)現(xiàn)的最簡(jiǎn)單的query方式,通過(guò)shell命令調(diào)用sqlite執(zhí)行sql語(yǔ)句:
public function query($str) {
$cmd = sprintf('sqlite3 %s "%s"', $this->config['params']['dbfile'], $str);
exec($cmd, $arr);
}
當(dāng)然這個(gè)只是示例,ThinkPHP本身就支持sqlite3,通過(guò)pdo的方式去連接就可以。實(shí)際的應(yīng)用環(huán)境可能是通過(guò)連接4層協(xié)議訪問(wèn)中間層端口獲取數(shù)據(jù)。
四、Behavior行為擴(kuò)展
Behavior行為設(shè)計(jì)是ThinkPHP框架的核心,通過(guò)行為配置和擴(kuò)展,為系統(tǒng)的伸縮性和定制性提供了最大的支持。
假如我們要加入登錄驗(yàn)證的功能,按照常規(guī)我們會(huì)設(shè)計(jì)自己的父類Controller,然后所有其他的Controller都從這里繼承。但有了Behavior會(huì)變得更加簡(jiǎn)單和靈活,我們只需要在tags.php(沒(méi)有的話在配置目錄新建)添加一個(gè)Behavior就可以了:
return array(
'action_begin' => array('Ucai\Behavior\AuthBehavior'),
'view_begin' => array('Ucai\Behavior\OutputBehavior'),
);
程序在執(zhí)行到action_begin流程時(shí)就會(huì)調(diào)用這個(gè)Behavior,我們可以根據(jù)狀態(tài)進(jìn)行跳轉(zhuǎn)或終止執(zhí)行。
namespace Ucai\Behavior;
class AuthBehavior {
// 行為擴(kuò)展的執(zhí)行入口必須是run
public function run(&$return) {
//不需要驗(yàn)證的action設(shè)置為true
if (!$return['AUTH_PUBLIC']) {
if (service('User')->checkLogin())
{
$return = true;
}
else
{
header('Content-Type: text/html; charset=utf-8');
redirect(U('User/index', array('url' => $_SERVER['HTTP_REFERER'])), 5, '需要登錄,5秒后跳轉(zhuǎn)。。。');
}
}
}
}
對(duì)于不需要登錄的頁(yè)面我們可以在Controller里添加配置,所有不配置的都會(huì)要求登錄驗(yàn)證。
public $config = array('AUTH_PUBLIC' => true);
這里大家對(duì)繼承和Behavior實(shí)現(xiàn)登錄驗(yàn)證做一個(gè)對(duì)比,可能覺(jué)得區(qū)別不大。但是在一個(gè)復(fù)雜的項(xiàng)目里,這種功能會(huì)非常多,如果每個(gè)功能都放到父類里,就會(huì)非常龐大,并且部分子類可能又不需要,這時(shí)候用Behavior去定制流程就會(huì)顯得游刃有余。
在上面的配置中我們還發(fā)現(xiàn)了一個(gè)配置OutputBehavior更能說(shuō)明問(wèn)題,大家有沒(méi)有猜到,這個(gè)Behavior我是用來(lái)在view里輸出一些共有變量,例如jscss的域名和路徑等。在沒(méi)有Behavior之前,大家是不是需要一個(gè)公共方法,然后每個(gè)頁(yè)面都去調(diào)用一次,或者改寫View的類代碼?有了Behavior就顯得方便許多。
namespace Ucai\Behavior;
class OutputBehavior {
public function run(&$return) {
$view = \Think\Think::instance('Think\View');
$view->assign('STATIC_URL', 'http://p3.ucai.cn/static');
}
}
擴(kuò)展總結(jié):通過(guò)Behavior擴(kuò)展和數(shù)據(jù)庫(kù)驅(qū)動(dòng)擴(kuò)展大家可以看到,ThinkPHP提供了很靈活的擴(kuò)展和增強(qiáng)機(jī)制,能滿足眾多需求。其他存儲(chǔ)、緩存、日志、模板引擎等如果需要也能很方便的擴(kuò)展。
五、源碼分析與不足
首先我們來(lái)分析一下框架執(zhí)行的大致流程:
index.php(入口、調(diào)試模式、應(yīng)用路徑)
--> ThinkPHP.php(定義路徑與訪問(wèn)模式)
--> Think\Think(類加載器、異常處理、讀取共有配置)
--> Think\App(請(qǐng)求url調(diào)度解析、執(zhí)行調(diào)度解析結(jié)果)
--> exec 執(zhí)行用戶定義的Controller的Action方法
--> Think\Dispatcher(根據(jù)url模式解析M、C、A和參數(shù),加載模塊配置)
--> Think\Controller(調(diào)用視圖、包裝和重定向)
可以看到,框架的內(nèi)部流程其實(shí)比較簡(jiǎn)單,還有2個(gè)很重要的類:
Think\Hook: 監(jiān)聽(tīng)App、Action、View的各個(gè)階段,執(zhí)行Behavior
Think\Behavior: 可配置(配置文件)可增刪(代碼)
在分析源代碼的過(guò)程中,我們也看到了一些不足:
1、宏定義過(guò)多,難于維護(hù)和修改
建議:只在個(gè)別文件定義極少數(shù)幾個(gè)宏,其余用類常量包裝
2、面向過(guò)程代碼過(guò)多,封裝不清晰
建議:用面向?qū)ο笏枷氚b
例如:url的解析和包裝,現(xiàn)在是在Dispatcher里生成APP宏,然后在U方法里讀取宏并生成最終url。其實(shí)完全可以定義一個(gè)類來(lái)包裝例如UrlHelper,而類的二個(gè)方法parse和generate分別負(fù)責(zé)解析和生成url,這樣代碼結(jié)構(gòu)會(huì)清晰很多。
3、有的函數(shù)和類代碼封裝過(guò)多,復(fù)用和改進(jìn)不方便
建議:用組合來(lái)封裝獨(dú)立功能內(nèi)容
例如:Model的校驗(yàn)功能,完全可以獨(dú)立成類,也可以用于非Model對(duì)象調(diào)用。而現(xiàn)在的校驗(yàn)接口是Model的保護(hù)性方法,只能在Model的create函數(shù)調(diào)用,外面必須通過(guò)create方法才能校驗(yàn)。
4、代碼規(guī)范和風(fēng)格問(wèn)題
希望代碼風(fēng)格能更加規(guī)范和標(biāo)準(zhǔn),例如DB類作為模板方法的父類,應(yīng)該用抽象方法或拋出異常形式定義所有Model需用到的方法。事實(shí)上有些方法子類是不需要的,而Db類卻沒(méi)有實(shí)現(xiàn)。
六、總結(jié)
ThinkPHP作為國(guó)內(nèi)熱門的php框架,確實(shí)給我們的開(kāi)發(fā)帶來(lái)了便利。框架開(kāi)發(fā)者對(duì)web流程理解的很透徹,對(duì)php的函數(shù)應(yīng)用爐火純青??蚣芏x了靈活的配置和擴(kuò)展適應(yīng)各種需求,提供了豐富的組件和模塊來(lái)加速開(kāi)發(fā)。最后說(shuō)一點(diǎn),ThinkPHP的文檔和社區(qū)支持非常完善,這也是框架流行不可缺少的重要一環(huán)。我們也希望ThinkPHP以后能更加完善自身的結(jié)構(gòu),打造成最優(yōu)秀的php框架。
- ThinkPHP應(yīng)用模式擴(kuò)展詳解
- Thinkphp 框架擴(kuò)展之Widget擴(kuò)展實(shí)現(xiàn)方法分析
- Thinkphp 框架擴(kuò)展之行為擴(kuò)展原理與實(shí)現(xiàn)方法分析
- Thinkphp 框架擴(kuò)展之標(biāo)簽庫(kù)驅(qū)動(dòng)原理與用法分析
- Thinkphp 框架擴(kuò)展之?dāng)?shù)據(jù)庫(kù)驅(qū)動(dòng)常用方法小結(jié)
- Thinkphp 框架擴(kuò)展之類庫(kù)擴(kuò)展操作詳解
- thinkphp框架類庫(kù)擴(kuò)展操作示例
- thinkphp5框架實(shí)現(xiàn)的自定義擴(kuò)展類操作示例
- ThinkPHP行為擴(kuò)展Behavior應(yīng)用實(shí)例詳解
- ThinkPHP的Widget擴(kuò)展實(shí)例
- Thinkphp 框架擴(kuò)展之應(yīng)用模式實(shí)現(xiàn)方法分析
相關(guān)文章
PHP隊(duì)列場(chǎng)景以及實(shí)現(xiàn)代碼實(shí)例詳解
這篇文章主要介紹了PHP隊(duì)列場(chǎng)景以及實(shí)現(xiàn)代碼實(shí)例詳解,有感興趣的同學(xué)可以跟著學(xué)習(xí)研究下2021-02-02PHP網(wǎng)站自動(dòng)化配置的實(shí)現(xiàn)方法(必看)
下面小編就為大家?guī)?lái)一篇PHP網(wǎng)站自動(dòng)化配置的實(shí)現(xiàn)方法(必看)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05PHP 中使用explode()函數(shù)切割字符串為數(shù)組的示例
explode()函數(shù)的作用:使用一個(gè)字符串分割另一個(gè)字符串,打散為數(shù)組。下面通過(guò)本文給大家介紹PHP 中使用explode()函數(shù)切割字符串為數(shù)組 ,需要的朋友可以參考下2017-05-05uni-app結(jié)合PHP實(shí)現(xiàn)單用戶登陸demo及解析
這篇文章主要為大家介紹了uni-app結(jié)合PHP實(shí)現(xiàn)單用戶登陸示例過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05ThinkPHP的MVC開(kāi)發(fā)機(jī)制實(shí)例解析
這篇文章主要介紹了ThinkPHP的MVC開(kāi)發(fā)機(jī)制實(shí)例解析,通過(guò)一個(gè)完整的實(shí)例講述MVC的原理,需要的朋友可以參考下2014-08-08php在程序中將網(wǎng)頁(yè)生成word文檔并提供下載的代碼
在php程序文件中生成內(nèi)容到word文檔中并提供下載功能的實(shí)現(xiàn)代碼,需要的朋友可以參考下2012-10-10