市面上常見的php框架有不少,最近由於有技術需求,因此對常見的php框架的中間件進行了一些瞭解。各個框架儘管在目標上對php框架的定義大同小異,可是在實現方式上卻各有不一樣,且看下文:php
首先什麼是php的中間件?nginx
根據zend-framework中的定義:git
所謂中間件是指提供在請求和響應之間的,可以截獲請求,並在其基礎上進行邏輯處理,與此同時可以完成請求的響應或傳遞到下一個中間件的代碼。github
這一介紹十分的簡潔,但卻略顯抽象,接下來咱們經過例子來一個個看。api
首先來看CI框架,php star數 12830.
做爲一款很是簡潔的框架,CI被吐槽的很多,可是也有不少人喜歡。首先來看它官方給出的一張請求時序圖:跨域
根據上文中對中間件的定義,那麼對於CI框架來講,惟一稱得上是內置中間件的:Security模塊瀏覽器
Security模塊是在請求進入controller以前實現的邏輯:緩存
乍看起來,CI框架的中間件十分的侷限,可是其實它卻提供了無限的可能性。。由於CI中還提供了一個叫作Hooks的功能。即鉤子。php框架
下面來看兩個個hooks的例子:安全
定義一個在controller邏輯以前的鉤子,並指定鉤子的參數、類名或函數名信息:
$hook['pre_controller'] = array( 'class' => 'MyClass', 'function' => 'Myfunction', 'filename' => 'Myclass.php', 'filepath' => 'hooks', 'params' => array('beer', 'wine', 'snacks') );
定義一個在controller邏輯以後的鉤子,並直接給出其實現:
$hook['post_controller'] = function() { /* do something here */ };
爲何說CI沒提供什麼像樣的中間件可是又很靈活呢,就是由於它能夠在以下的多個階段進行掛鉤子的操做。細數過來有7種之多。
從後文中能夠看出,不少其餘的框架可能也就會涵蓋兩三種階段,所以,從這個角度上來講,CI的鉤子組合而成的中間件的確很靈活。
$this->CI =& get_instance()
方法來獲取 CI 超級對象,以及使用 $this->CI->output->get_output()
方法來 獲取最終的顯示數據;總結來看,CI中的中間件:
github star 24997
做爲最近兩年大紅大紫的Laravel,的確也是有必要對其中間件機制進行了解:
首先Laravel提供了一個很好的中間件自動生成工具:php artisan make:middleware OldMiddleware
由Laravel的命令行完成,這種看似簡單的命令行工具其實能夠對框架的擴展起到很是重要的做用。
再來看一個Laravel中典型的請求過濾器:
<?php namespace App\Http\Middleware; use Closure; class OldMiddleware { /** * 運行請求過濾器。 * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { if ($request->input('age') <= 200) { return redirect('home'); } return $next($request); } }
過濾器,filter,是中間件中使用最普遍的一種,不少框架裏甚至filter就等同於中間件。意如其名,便是對請求Request進行某種過濾,這個過濾能夠是參數上的限制、安全策略的限制、http協議的限制,只要是請求中帶來的屬性,均可以據此進行過濾。
同時這裏也能夠看到,Laravel使用閉包的方式進行請求的傳遞,真正踐行的優雅的中間件串聯的方式,只須要調用next函數,請求便可被按照預先定義的規則傳遞到下一個中間件中。
Laravel支持全局的中間件和根據具體路由規定的中間件兩種,同時優先級又以定義順序爲準。作到全局與具體狀況的兼顧。同時它顯示的支持前置、後置和Terminable三種中間件,覆蓋了大部分的中間件場景,是一種相對不錯的設計。
但美中不足或者說場景覆蓋不夠友好的地方在於它以路由的方式組織中間件,會與controller有些脫節,每次定義controller中action行爲的時候,還須要轉換爲路由進行配置,略有些不方便。
總結來看
github star 4668
yii框架首先是中國人開發的,star數雖然不是不少,可是功能也算豐富。
yii框架從1.1到2.0,通過了一個比較大的升級,支持了不少新的特性,若是不支持,只怕是要落伍了。
在yii框架1.1中,中間件乾脆就叫filters了,十分的直白,分爲pre-filter和post-fiter兩種,即前文中說的,在進入controller以前的過濾邏輯,和完成controller處理以後的過濾邏輯。
可是到了yii2.0以後,filters通過了一層升級,到了behaviors,明確了一點:重心放在了每個controller的行爲上,而不是像Laravel同樣controller很傻很單純。
yii框架的behaviors能夠在controller或application中配置。
這裏是一個訪問控制的filter,具體進行什麼樣的訪問控制由className定義,同時對controller中的action支持「only」關鍵字,還有「」關鍵字,可以支持排除法的功能,這個在一些場景下仍是頗有用的。同時「roles」也可以支持你預先定義好的角色的概念,好比學生沒法訪問教師後臺,而教師沒法訪問學生論壇等。
use yii\filters\AccessControl; public function behaviors() { return [ 'access' => [ 'class' => AccessControl::className(), 'only' => ['create', 'update'], 'rules' => [ // allow authenticated users [ 'allow' => true, 'roles' => ['@'], ], // everything else is denied by default ], ], ]; }
固然,在Yii中你也能夠自定義filter:
namespace app\components; use Yii; use yii\base\ActionFilter; class ActionTimeFilter extends ActionFilter { private $_startTime; public function beforeAction($action) { $this->_startTime = microtime(true); return parent::beforeAction($action); } public function afterAction($action, $result) { $time = microtime(true) - $this->_startTime; Yii::trace("Action '{$action->uniqueId}' spent $time second."); return parent::afterAction($action, $result); } }
這裏明顯能夠看出,這個filter針對action,分別在「beforeAction」和「afterAction」兩個階段進行了邏輯處理,完成了請求的計時工做。
因此總的來看,Yii框架中的中間件:
ZendFramework是由zend公司推出的php框架,其目標就是創建一套大而全的php框架。以知足企業應用開發的目標。
ZendFramework由不少不一樣的模塊構成,使用者能夠經過相互組合的方式來實現本身想要的功能,同時也可以不一次加載大而全的框架,十分的靈活。
好比有負責受權的"zend-authentication",或者是負責驗證碼的"zend-captcha"等等。
其中"zend-stratigility" 負責提供中間件以及中間件執行流的功能。
use Zend\Stratigility\MiddlewarePipe; use Zend\Diactoros\Server; require __DIR__ . '/../vendor/autoload.php'; $app = new MiddlewarePipe(); $server = Server::createServer($app, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES); // Landing page $app->pipe('/', function ($req, $res, $next) { if (! in_array($req->getUri()->getPath(), ['/', ''], true)) { return $next($req, $res); } return $res->end('Hello world!'); }); // Another page $app->pipe('/foo', function ($req, $res, $next) { return $res->end('FOO!'); }); $server->listen();
這裏的代碼給出了兩個中間件的例子。第一個是落地頁,監聽了root路徑,若是命中了這一路由規則,那麼請求會被提早結束,返回給用戶「Hello world!」。
而第二個中間件去匹配foo這一路徑,模糊匹配的方式,若是命中了,會返回FOO並結束請求。
與Laravel相似,這裏一樣支持使用next(可調用的變量)的方式將請求繼續向下傳遞。而這裏中間件配置的方式也跟Laravel比較像,是統一在一個地方根據路由進行配置的,這樣徹底能夠按照以下的方式根據不一樣的路由定義不一樣的中間件處理邏輯:
$app->pipe('/api', $apiMiddleware); $app->pipe('/docs', $apiDocMiddleware); $app->pipe('/files', $filesMiddleware);
總結來看,ZendFramework的中間件:
首先按照不一樣的類別列舉一下常見的中間件:
因此一個php框架最好可以: