ThinkPHP框架設計與擴展總結

原文詳見:http://www.ucai.cn/blogdetail/7028?mid=1
還能在線運行查看效果哦php

導言:ThinkPHP框架是國內知名度很高應用很普遍的php框架,咱們從一些簡單的開發示例中來深刻了解一下這個框架給咱們帶來的開發便捷性,以及遊刃有餘的擴展設計。同時也從源碼分析的角度看看框架的一些不足,儘可能作全面客觀的評價。這裏假設你們已經使用過ThinkPHP框架,基本使用方法請參考官方文檔。css

1、框架分層及url路由
框架的安裝很是簡單,下載後放入web服務器的目錄便可,可是建議你們不要用默認的入口文件位置,而是放入單獨的目錄,便於保護代碼和數據。例如個人入口文件和web服務器配置目錄在web目錄(外層框架裏的index.php沒有刪除可是沒有使用):
請輸入圖片描述html

同大多數MVC框架同樣,咱們只須要按框架的目錄結構,擴展本身的Controller和View,一些頁面就開發完成了。ThinkPHP提供Module、Controller、Action三層結構來組織本身的url(3.1版本叫分組、Action和method,3.2更加國際範),目錄結構以下:
請輸入圖片描述mysql

這裏強烈建議你們:
一、業務單獨分層,不用放在Controller和Model裏,例如我這裏經過擴展函數庫Application/Common/Common/function.php強制定義業務層名稱爲Service:web

function service($name)
{
    return D($name, 'Service');
}

好處是複用性好,假如未來要開發wap頁面,寫了不一樣的Controller,就能夠複用service,假如之後的數據存儲變了,好比把數據庫從mysql遷移到mongodb之類,那修改Model就能夠,service仍是不須要任何修改。
二、基礎模塊和業務模塊分開,不要相互引用。基礎模塊(例如用戶基本信息)只提供數據接口沒有Controller和View。
三層目錄已經能夠應對通常的web應用,更加複雜的web應用咱們能夠定義不一樣的入口文件加載不一樣的Application來解決。更更復雜的應用?門戶和超大規模網站麼,那就不是一個php框架能解決全部問題的了,須要本身的中間件和定製框架。正則表達式

ThinkPHP的支持4種url訪問模式,分別是:
一、普通模式,傳統url模式,全部參數分開,例如
http://localhost/tp/index.php?m=Ucai&c=User&a=index&para=xxx
路由參數:m參數表示模塊,c表示控制器,a表示訪問方法
二、兼容模式
http://localhost/tp/index.php?s=/Ucai/User/index/para/xxx
路由參數經過s參數組裝,固然數據參數也能夠沒必要放在s參數裏
三、pathinfo模式
http://localhost/tp/index.php/Ucai/User/index/para/xxx
這種模式把入口文件和真實腳本放在一塊兒,含義明確,也便於SEO
四、rewrite模式
http://localhost/tp/Ucai/User/index/para/xxx
這種模式經過web服務器的rewrite配置隱藏入口文件,顯得更加友好
其中pathinfo和rewrite模式須要web服務器支持。ThinkPHP有個配置須要設置爲哪一種模式,實際上是用在U方法裏生成url連接的時候用到的,訪問的時候只要web服務器支持用哪一種方式均可以。
也建議ThinkPHP其實不須要配置,而是記住用戶訪問的方式,只要第一個訪問用的是哪一種模式,之後生成的url都用這種方式生成,由於用戶都已經訪問到了就不存在支不支持的問題了。sql

若是正常的url不能達到咱們的要求,還能夠經過配置路由進一步優化url,例如咱們想把url配置的更加簡單
http://localhost/tp/Ucai/login/xxx
咱們只須要在模塊配置文件中添加以下的路由配置便可,若是用正則表達式則能夠更加簡化mongodb

'URL_ROUTE_RULES'   =>  array(
        'login/:para' => 'Ucai/User/index',
        'login' => 'Ucai/User/index',
    ),

到這裏咱們能夠看到,ThinkPHP框架支持的層次結構和url配置很是豐富,能知足各類不一樣的需求。固然咱們建議你們不要濫用路由配置,適當少許的配置能帶來更好的seo效果,可是大量的配置會給項目的維護和修改帶來困難。shell

2、ThinkPHP擴展
ThinkPHP自己含有豐富的組件和驅動,咱們以數據庫驅動擴展和行爲擴展爲例來了解一下ThinkPHP的擴展設計。數據庫

3、數據庫驅動擴展
雖然ThinkPHP提供了衆多的數據庫驅動,可是也並不能知足全部的需求。例如咱們的數據極可能不是經過直接訪問數據庫去實現,而是經過一些中間件(例如C程序)進行轉發,從而得到更好的性能,這時就須要擴展數據庫驅動來支持。
擴展很是簡單,在DB/Driver目錄下新建本身的驅動,例如Custom.php,而後實現request和execute方法擴展就算完成了,而後再配置文件裏配置DB_TYPE=’custom’,就可使用了。這裏的request表示查詢,execute表示更改數據,全部其餘操做都會在Model裏進行解析,包裝成sql語句調用這兩個方法執行。
例如我所實現的最簡單的query方式,經過shell命令調用sqlite執行sql語句:

public function query($str) {
        $cmd = sprintf('sqlite3 %s "%s"', $this->config['params']['dbfile'], $str);
        exec($cmd, $arr);
}

固然這個只是示例,ThinkPHP自己就支持sqlite3,經過pdo的方式去鏈接就能夠。實際的應用環境多是經過鏈接4層協議訪問中間層端口獲取數據。

4、Behavior行爲擴展

Behavior行爲設計是ThinkPHP框架的核心,經過行爲配置和擴展,爲系統的伸縮性和定製性提供了最大的支持。
假如咱們要加入登陸驗證的功能,按照常規咱們會設計本身的父類Controller,而後全部其餘的Controller都從這裏繼承。但有了Behavior會變得更加簡單和靈活,咱們只須要在tags.php(沒有的話在配置目錄新建)添加一個Behavior就能夠了:

return array(
    'action_begin' => array('Ucai\Behavior\AuthBehavior'),
    'view_begin' => array('Ucai\Behavior\OutputBehavior'),
);

程序在執行到action_begin流程時就會調用這個Behavior,咱們能夠根據狀態進行跳轉或終止執行。

namespace Ucai\Behavior;
class AuthBehavior {
     // 行爲擴展的執行入口必須是run
     public function run(&$return) {
        //不須要驗證的action設置爲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秒後跳轉。。。');
            }
         }
     }
}

對於不須要登陸的頁面咱們能夠在Controller裏添加配置,全部不配置的都會要求登陸驗證。

public $config = array('AUTH_PUBLIC' => true);

這裏你們對繼承和Behavior實現登陸驗證作一個對比,可能以爲區別不大。可是在一個複雜的項目裏,這種功能會很是多,若是每一個功能都放到父類裏,就會很是龐大,而且部分子類可能又不須要,這時候用Behavior去定製流程就會顯得遊刃有餘。
在上面的配置中咱們還發現了一個配置OutputBehavior更能說明問題,你們有沒有猜到,這個Behavior我是用來在view裏輸出一些共有變量,例如jscss的域名和路徑等。在沒有Behavior以前,你們是否是須要一個公共方法,而後每一個頁面都去調用一次,或者改寫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');
     }
}

擴展總結:經過Behavior擴展和數據庫驅動擴展你們能夠看到,ThinkPHP提供了很靈活的擴展和加強機制,能知足衆多需求。其餘存儲、緩存、日誌、模板引擎等若是須要也能很方便的擴展。

5、源碼分析與不足
首先咱們來分析一下框架執行的大體流程:
index.php(入口、調試模式、應用路徑)
--> ThinkPHP.php(定義路徑與訪問模式)
--> Think\Think(類加載器、異常處理、讀取共有配置)
--> Think\App(請求url調度解析、執行調度解析結果)
--> exec 執行用戶定義的Controller的Action方法
--> Think\Dispatcher(根據url模式解析M、C、A和參數,加載模塊配置)
--> Think\Controller(調用視圖、包裝和重定向)
能夠看到,框架的內部流程其實比較簡單,還有2個很重要的類:
Think\Hook: 監聽App、Action、View的各個階段,執行Behavior
Think\Behavior: 可配置(配置文件)可增刪(代碼)

在分析源代碼的過程當中,咱們也看到了一些不足:
一、宏定義過多,難於維護和修改
建議:只在個別文件定義極少數幾個宏,其他用類常量包裝
二、面向過程代碼過多,封裝不清晰
建議:用面向對象思想包裝
例如:url的解析和包裝,如今是在Dispatcher裏生成APP宏,而後在U方法裏讀取宏並生成最終url。其實徹底能夠定義一個類來包裝例如UrlHelper,而類的二個方法parse和generate分別負責解析和生成url,這樣代碼結構會清晰不少。
三、有的函數和類代碼封裝過多,複用和改進不方便
建議:用組合來封裝獨立功能內容
例如:Model的校驗功能,徹底能夠獨立成類,也能夠用於非Model對象調用。而如今的校驗接口是Model的保護性方法,只能在Model的create函數調用,外面必須經過create方法才能校驗。
四、代碼規範和風格問題
但願代碼風格能更加規範和標準,例如DB類做爲模板方法的父類,應該用抽象方法或拋出異常形式定義全部Model需用到的方法。事實上有些方法子類是不須要的,而Db類卻沒有實現。

6、總結 ThinkPHP做爲國內熱門的php框架,確實給咱們的開發帶來了便利。框架開發者對web流程理解的很透徹,對php的函數應用爐火純青。框架定義了靈活的配置和擴展適應各類需求,提供了豐富的組件和模塊來加速開發。最後說一點,ThinkPHP的文檔和社區支持很是完善,這也是框架流行不可缺乏的重要一環。咱們也但願ThinkPHP之後能更加完善自身的結構,打形成最優秀的php框架。

相關文章
相關標籤/搜索