欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

ThinkPHP3.1快速入门(22)行为

shiping1 的头像

概述

行为(Behavior)是ThinkPHP扩展机制中比较关键的一项扩展,行为既可以独立调用,也可以绑定到某个标签中进行侦听,官方提出的CBD模式中行为也占了主要的地位,可见行为在ThinkPHP框架中意义非凡。
这里指的行为是一个比较抽象的概念,你可以想象成在应用执行过程中的一个动作或者处理,在框架的执行流程中,各个位置都可以有行为产生,例如路由检测是一个行为,静态缓存是一个行为,用户权限检测也是行为,大到业务逻辑,小到浏览器检测、多语言检测等等都可以当做是一个行为,甚至说你希望给你的网站用户的第一次访问弹出Hello,world!这些都可以看成是一种行为,行为的存在让你无需改动框架和应用,而在外围通过扩展或者配置来改变或者增加一些功能。
而不同的行为之间也具有位置共同性,比如,有些行为的作用位置都是在应用执行前,有些行为都是在模板输出之后,我们把这些行为发生作用的位置称之为标签(位),当应用程序运行到这个标签的时候,就会被拦截下来,统一执行相关的行为,类似于AOP编程中的“切面”的概念,给某一个切面绑定相关行为就成了一种类AOP编程的思想。

系统标签位

系统核心提供的标签位置包括下面几个(按照执行顺序排列):
app_init应用初始化标签位
path_infoPATH_INFO检测标签位
route_check路由检测标签位
app_begin应用开始标签位
action_name操作方法名标签位
action_begin控制器开始标签位
view_begin视图输出开始标签位
view_template视图模板解析标签位
view_parse视图解析标签位
view_filter视图输出过滤标签位
view_end视图输出结束标签位
action_end控制器结束标签位
app_end应用结束标签位
在每个标签位置,可以配置多个行为定义,行为的执行顺序按照定义的顺序依次执行。除非前面的行为里面中断执行了(某些行为可能需要中断执行,例如检测机器人或者非法执行行为),否则会继续下一个行为的执行。
除了这些系统内置标签之外,开发人员还可以在应用中添加自己的应用标签,例如我们给应用的公共Action类CommonAction添加一个action_init标签位。
  1. Class CommonAction extends Action{
  2.     Public function _initialize(){
  3.         tag('action_init'); // 添加action_init 标签
  4.     }
  5.  }
复制代码
 
注意:tag函数用于设置某个标签位,可以传入并且只接受一个参数,如果需要传入多个参数,请使用数组,该参数为引用传值,所以只能传入变量。

核心行为

新版系统的很多核心功能也是采用行为扩展组装的,虽然在开发过程中可能感觉不到这种变化,但正是由于这种架构设计的改变,让新版变得更加灵活和易扩展,这是一个里程碑式的改变,对于满足项目日益纷繁复杂的需求和定制底层框架提供了更多的方便和可能性。
框架核心内置的行为包括如下:
行为名称说明对应标签位置
checkRoute路由检测行为,完成内置的路由功能route_check
LocationTemplate模板定位行为,完成模板文件自动定位和输出规则view_template
ParseTemplate模板文件解析,并支持第三方模板引擎驱动view_parse
ShowPageTrace页面Trace功能行为,完成页面Trace功能view_end
ShowRuntime运行时间显示行为,完成运行时间显示view_filter
TokenBuild令牌生成行为,完成表单令牌的自动生成view_filter
ReadHtmlCache读取静态缓存行为app_init
WriteHtmlCache生成静态缓存行为view_filter

行为定义

行为类的命名采用:行为名称(驼峰法,首字母大写)+Behavior 行为类的定义方式如下:
  1. class TestBehavior extends Behavior {
  2.         // 行为参数定义
  3.         protected $options   =  array(
  4.             'test_param'        => false,   //  行为参数 会转换成TEST_PARAM配置参数
  5.         );
  6.         // 行为扩展的执行入口必须是run
  7.         public function run(&$params){
  8.             if(C('TEST_PARAM')) {
  9.                 echo 'RUNTEST BEHAVIOR '.$params;
  10.             }
  11.         }
  12.  }
复制代码
 
行为类必须继承Behavior类,并且必须定义执行入口方法run(&$params); 由于行为的调用机制影响,run方法不需要任何返回值,所有返回都通过引用返回。每个行为类可以定义options属性,该属性中的参数会自动转换成单独配置参数,也就是说该参数可以用全局的C方法直接读取或者修改,同时也意味着行为中定义的options参数只是提供一个默认值,你完全可以在配置文件中或者使用C方法动态配置生效,而不需要手动传入行为类。这是Behavior类提供的方便和全局配置对接的一个特性,当然你完全可以不依赖这个特性。
因此,上面的run方法实现也可以更改为:
  1.         public function run(&$params){
  2.             if($this->test_param) {
  3.                 echo 'RUNTEST BEHAVIOR '.$params;
  4.             }
  5.         }
复制代码
 
run方法的参数只有一个,但支持传入数组。
行为类是支持自动加载的,其放置的位置可以包括如下位置,可以根据需要自行选择:
位置所在目录说明
核心行为目录ThinkPHP/Lib/Behavior/通常用于放置一些核心的内置行为
扩展行为目录Extend/Behavior/这是ThinkPHP扩展的行为扩展目录,第三方的扩展大都在此
项目的行为目录项目目录/Lib/Behavior/用于项目自身的行为扩展
独立分组的行为目录独立分组目录/Behavior/如果采用了独立分组的话,也可以把行为类放在这里
官方扩展包的行为扩展都位于Extend/Behavior/目录下面。

行为绑定

行为定义完成后,就需要绑定到某个标签位置才能生效,否则是不会执行的。
我们需要在项目的行为定义文件tags.php文件中进行行为和标签的位置定义,格式如下:
  1.     return array(
  2.         '标签名称'=>array('行为名1','行为名2',...), 
  3.     );
复制代码
 
标签名称包括我们前面列出的系统标签和应用中自己定义的标签名称,比如你需要在app_init标签位置定义一个CheckLangBehavior行为类的话,可以使用:
  1. return array(
  2.      'app_init'=>array('CheckLang'),
  3.  );
复制代码
 
可以给一个标签位定义多个行为,行为的执行顺序就是定义的先后顺序,例如:
  1. return array(
  2.      'app_init'=>array('CheckLang','CronRun'),
  3.  );
复制代码
 
默认情况下tags.php中定义的行为会并入系统行为一起执行,也就是说如果系统的行为定义中app_init标签中已经定义了其他行为,则会首先执行系统行为扩展中定义的行为,然后再执行项目行为中定义的行为,如果你希望项目tags中定义的行为完全替换系统的行为扩展,可以使用:
  1. return array(
  2.      'app_init'=>array('CheckLang','CronRun','_overlay'=>1),
  3.  );
复制代码
 
应用行为的定义没有限制,你可以把一个行为绑定到多个标签位置执行,例如:
  1.     return array(
  2.         'app_begin'=>array('Test'), // 在app_begin 标签位添加Test行为
  3.         'app_end'=>array('Test'), // 在app_end 标签位添加Test行为
  4.     );
复制代码
 
为了避免混淆,自定义的行为扩展尽量不要和核心的行为扩展重名。
除了定义tags行为配置文件之外,框架还提供了动态添加行为到标签位的方法,例如我们可以使用下面的方式添加Test行为到app_end标签位,而无需在tags文件中添加定义:
  1. add_tag_behavior'app_end','Test');
复制代码
 
表示把Test行为添加到app_end标签位的最后,你可以把这个代码放到项目的公共函数文件中甚至直接放到行为类的最后(如果你确定这个行为扩展只有你的项目会用到的话)。

单独执行

有时候,行为的调用不一定要放到标签才能调用,如果需要的话,我们可以在控制器中直接调用行为。例如,我们可以把用户权限检测封装成一个行为类,例如:
  1. class AuthCheckBehavior extends Behavior {
  2.     // 行为参数定义
  3.     protected $options   =  array(
  4.     'USER_AUTH_ON'        =>false,   //  是否开启用户认证
  5.     'USER_AUTH_ID'        => 'user_id',   //  定义用户的id为权限认证字段
  6.     );
  7.     // 行为扩展的执行入口必须是run
  8.     public function run(&$return){
  9.         if(C('USER_AUTH_ON ')) {
  10.             // 进行权限认证逻辑 如果认证通过 $return = true;
  11.             // 否则用halt输出错误信息
  12.         }
  13.     }
复制代码
 
定义了AuthCheck行为后,然后在_initialize方法中直接用下面的方式调用:
  1. B('AuthCheck');
复制代码
 
注意:因为这种方式的行为调用需要在相关位置添加代码,所以一般只有在应用代码才直接使用B方法调用。

总结

说了这么多,只是让你了解ThinkPHP中的行为的概念和运行机制,至于如何用好行为,以及怎么封装行为和定义标签还需要多实践了。相信很多熟悉ThinkPHP的开发者一定可以通过行为扩展来更方便的给框架增加功能了。
评论(38相关
solomon_zjf12月09日
这里还是3.1的教程吧,,3.2怎么弄呢。那个好人介绍下区别
GameLife__Dream07月28日
和laravel里面的middleware一样,单又比中间件更高级
牛角07月17日
看了下一头雾水,tag这个单词和使用的场景完全不匹配,为什么不用 triggerEvent 和 onEvent 之类的单词
qf199106232014年12月10日
太抽象了,很难看懂,给个例子,具体可以实现什么功能
oodece2014年11月14日
试了一下分组(不是独立分组),貌似不行!!!
ywmprogrammer2014年10月17日
tags.php文件要定义在哪个目录啊
回复木杉05月04日
Conf
zhongqiu_cn2014年04月30日
没怎么懂,还是要看实例……
xingzhe2014年04月25日
感觉类似 Wordpress的 action和filter
戏子2014年04月22日
消化中……
灸月枫舞2014年04月08日
果然还得结合视频来看....
jintingbo2014年03月31日
我的理解:两个小偷偷东西,张三有张三的偷法,李四有李四的偷法,他们各自的偷法叫方法,张三的方法,李四不一定能用,李四的方法,张三不一定能用。所以,我们要讲他们俩偷东西的故事,得分别论述,很麻烦。偷法就是方法,就是Action。
为了减轻我们的劳动量,我们把他们的偷法当成一个故事来讲。于是考察他们的偷法,抽象一下,他们都是一种偷得行为。所以我再讲他们的故事的时候,就不分别讲他们的偷 东西的方法了,我只说他们偷得行为,这样省事。
于是我从thinkphp的行为中继承一个标准的行为,在这个行为中写偷的方法。以后张三再去偷东西时,就是调用我的行为中的偷,李四也一样。 
只要有两个或两个以上的,有共同爱好的,我都可以把这个爱好写成一个行为。
不知道我理解的对不对?
回复lcuzhanglei07月04日
好nb 的解释啊
回复thinkphp传奇11月06日
确实通熟!
回复solomon_zjf12月09日
膜拜一下
toby_li2014年02月11日
看了,云里雾里的
janry2013年12月23日
呵呵,这个解说的的确有点抽象,其实就是在某个代码位置调用一个回调事件,如果事件已经定义就调用,事件名其实就是标签名,哎,为毛不直接用观察者模式搞呢
zjkal2013年11月30日
这个功能不错,类似java的Spring框架中的面向切面编程,方便统一记录日志等操作。
tree1002013年11月23日
还没有用到!加油!
jiewuzhe022013年11月16日
噢,哦,嗯,(⊙o⊙)…
ablmti2013年11月16日
感觉不懂
phantomshop2013年08月31日
看起来吃力,太抽象
itaotao2013年08月16日
按官方的方法没有成功!Class TestBehavior contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Behavior::run)哎 不知道怎么用了
╰'安顁。2013年08月15日
不理解,行为和Action有什么区别
jroam2013年07月31日
我也没明白如何传入参数,在行为里获取不到$_request变量啊?怎么办呢?教程里也没有写.
╰'安顁。2013年07月24日
我是路过,但是忍不住来顶一顶。
回复zl1975785842013年09月18日
龙,你飞个吧
混世小子2013年07月05日
看了遍快速教程感觉还是有点晕,所以打算看一下视频教程!
王其越2013年07月01日
不是很理解,我绑定了行为之后,岂不是我的所有操作都被拦截了,但是如果我有部分的操作不希望被拦截,要怎么做呢
回复thinkphp2013年07月01日
这个可以在行为里面进行过滤或者判断
leo3147104722013年06月27日
单独执行中 
if(C('USER_AUTH_ON ')) {
此处多了个空格
blackfox2013年06月26日
不理解,希望出实例
xianglingchuan2013年06月16日
我感觉这个行为,就是在预定在某一个时间或者某一个动作的时候来执行这么一件事
xianglingchuan2013年06月16日
行为没有加载成功按例子来的
回复xianglingchuan2013年06月16日
好了,是文件名不正确的原因
zzggjjzgj2013年06月14日
这个到底有什么作用呢?给个实例!
hopestar862013年06月05日
太抽象了,能举个简单的应用,在什么地方怎么使用行为而达到灵活扩展的功能就比较好
zhuyuejianke2013年06月03日
行为 的教程 忽略了传入参数,其实每个行为的传入参数都是不同的,加上自己扩展的行为,那么多记忆是记不住的,直接看源码就会发现,所谓行为就是回调函数而已。回调函数的参数与此函数所处的位置有关。
回复thinkphp2013年06月03日
嗯 感谢提出,以后会补充下。
回复usausa1112013年06月08日
回复 thinkphp : 
这个很重要啊·我在Tags.php 里加载了
'view_begin' => array('SeoContent'),
系统加载的时候 在模板开始之前执行
我怎么获取 SeoContentBehavior 的 返回的值 或者说 怎么获取&$params 引用的
我在 run (){ return $a 或者 $params= array(...)}
怎么在 testAction 里面获取 SeoContentBehavior 的 return 或者是
SeoContentBehavior $params
不是很理解 &$params 这个东西
回复loongwong2013年07月09日
回复 usausa111 : 同问。我也对这个$params疑惑,还有如何获得run的返回值?$params是怎么传递进去的?
qzzm2013年05月15日
按照单独执行的例子
AuthCheckBehavior.php 放到项目目录App/Lib/Behavior下,
在控制器中添加
Public function _initialize() {
B('AuthCheck');
}
运行那个页面方法时,出现
Class 'AuthCheckBehavior' not found
错误位置
FILE: E:\wwwroot\Test\plugin\ThinkPHP\Common\common.php  LINE: 581
B方法加载不了这个行为,请问哪里出错了?
回复leo3147104722013年06月27日
AuthCheckBehavior.class.php ?
疯狂的土贼2013年05月03日
字和视频不同步的问题比较严重 视频压缩格式不好更别说是 2x速度看的时候 根本字和视频不同步 建议更改
your hero2013年04月22日
期待,有没有PHP学习群。大家可以交流下,要不我建一个,大家进来聊聊,222570496
didige2013年04月20日
哈哈,偶也来了
qiangqiangxi2013年04月09日
行为到底可以用来做啥呢! 迷茫哦!
回复yhhcbin2013年06月19日
+1
robinliu2013年04月08日
是呀,我们也非常期待。
tyua072013年04月08日
沙发 官网好久都没更新教程了?视频教程什么时候出?很期待啊!

普通分类: