市面上常见的php框架有很多,最近因为有技术需求,所以对常见的php框架的中间件进行了一些了解。各个框架尽管在目标上对php框架的定义大同小异,但是在实现方式上却各有不同,且看下文:
首先什么是php的中间件?
根据zend-framework中的定义:
所谓中间件是指提供在请求和响应之间的,能够截获请求,并在其基础上进行逻辑处理,与此同时能够完成请求的响应或传递到下一个中间件的代码。
这一介绍十分的简洁,但却略显抽象,接下来我们通过例子来一个个看。
首先来看CI框架,php star数 12830.
作为一款非常简洁的框架,CI被吐槽的不少,但是也有很多人喜欢。首先来看它官方给出的一张请求时序图:
根据上文中对中间件的定义,那么对于CI框架来说,唯一称得上是内置中间件的:Security模块
Security模块是在请求进入controller之前实现的逻辑:
乍看起来,CI框架的中间件十分的局限,但是其实它却提供了无限的可能性。。因为CI中还提供了一个叫做Hooks的功能。即钩子。
下面来看两个个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中典型的请求过滤器:
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框架最好能够:
以上