Behavior行为设计是ThinkPHP框架的核心,通过行为配置和扩展,为系统的伸缩性和定制性提供了最大的支持。
假如我们要加入登录验证的功能,按照常规我们会设计自己的父类Controller,然后所有其他的Controller都从这里继承。但有了Behavior会变得更加简单和灵活,我们只需要在tags.php(没有的话在配置目录新建)添加一个Behavior就可以了:
'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就显得方便许多。
class OutputBehavior {
public function run(&$return) {
$view = \Think\Think::instance('Think\View');
$view->assign('STATIC_URL', 'http://p3.ucai.cn/static');
}
}
扩展总结:通过Behavior扩展和数据库驱动扩展大家可以看到,ThinkPHP提供了很灵活的扩展和增强机制,能满足众多需求。其他存储、缓存、日志、模板引擎等如果需要也能很方便的扩展。
五、源码分析与不足
首先我们来分析一下框架执行的大致流程:
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: 可配置(配置文件)可增删(代码)
在分析源代码的过程中,我们也看到了一些不足: