Thinkphp——hook类行为扩展

来源:互联网 发布:mysql 存储图片base64 编辑:程序博客网 时间:2024/04/29 23:21

http://www.thinkphp.cn/topic/10206.html

行为扩展实际上就是在这些流程里埋下了一个钩子,你可以往钩子里添加你自己的业务逻辑,当程序执行到某个钩子位置时将自动触发你的业务逻辑,关于系统预置的一些钩子可以参考:


http://document.thinkphp.cn/manual_3_2.html#behavior_extend

1.TP内置行为钩子
我们知道TP中预留了一些行为钩子,比如 action_begin,这个钩子是在动作开始执行时触发,预置的钩子大家通过配置文件注册行为类,大家在Application/Common/Conf目录下创建一个tags.php,这个和3.1是一样的,返回一个数组,数组格式是 "钩子名"=>array("行为类1","行为类2"......)
这里我给一个例子:
Application/Common/Conf/tag.php:
<?php
return array(
 'app_init'     =>  array(             'Behavior\TestBehavior', // 生成运行Lite文件

        ),

   );
?>
可以看到,我往这个钩子里面注册了一个行为,这个行为就是Behaviors\\test 这里的写法是命名空间写法,其对应的类文件路径是:
library/Behaviors/testBehavior.class.php

Application/Behaviors/testBehavior.class.php:
<?php
namespace Behaviors;
class testBehavior{
function run($arg){
echo "这是一个行为扩展".$arg;
}
}
?>
千万要注意第一行的命名空间,对于命名空间不理解的请自行查阅php手册。另外对于TP的自动加载机制,参考手册:
http://document.thinkphp.cn/manual_3_2.html#autoload
行为的执行入口是 run()方法,触发钩子时会自动执行行为类里的run()方法。

2.动态添加钩子和注册行为
通过上面的例子大家才是了解了行为大概是个什么东西,但是对于其执行流程可能还不清楚,这里我来介绍下动态添加钩子和注册行为,使大家对行为执行机制有一个比较清晰的理解。
首先,行为钩子添加和注册行为类,以及触发行为,都是通过Hook类来实现的,Hook类在TP核心包里的ThinkPHP目录下,Hook.class.php.
>>添加钩子以及注册行为:\Think\Hook::add('钩子名','行为')
>>埋设/监听/触发钩子:\Think\Hook::listen('钩子名','传递给run的参数,必须是个变量');
假设我们需要在访问index.php/Public/login.html的时候触发login钩子里的行为,那么首先我们需要在login方法中监听钩子,也就是把钩子埋在login方法里,当访问login方法时就会自动触发,有点像猎人的陷阱不是吗?
function login(){
\Think\Hook::listen('login');//监听一个名为login的钩子
...其他代码略...
}
好了,我们在login方法里监听了login钩子,那么接下来我们往这个钩子里添加一些行为,这样访问login的时候会自动触发这些行为,执行行为类的run方法。
行为在哪里注册呢?
当然得在触发之前注册,1.你可以通过tags.php注册,上面提到过了,只不过把action_begin换成login。2.动态添加,假如你这个钩子只在Public控制器中使用,那么你可以在PublicController的_initialize()初始化方法中动态添加钩子。
function _initialize(){
\Think\Hook::add('login','Behaviors\\test');
}
这里就往login这个钩子里添加了一个test行为,比较懒直接从上面复制过来了,大家理解这个意思就可以。
添加多个行为的话可以这样
\Think\Hook::add('login',array('Behaviors\\test','Behaviors\\test1'...));
就是第二个参数变成一个数组,数组里每个元素对应一个行为类,注意,当钩子被触发时,这里面的所有行为都会依次执行。

3.带参数的行为
上面我们知道了行为是通过run()方法执行的,那么我们想传递一些参数进去怎么办呢?
答案是 \Think\Hook::listen(); 的第二个参数。
注意listen方法定义如下:
static public function listen($tag, &$params=NULL)
可以看到第二个参数是一个引用传递的参数,也就是说,第二个参数必须是一个变量,不能是值,下面的使用方法是错误的:
\Think\Hook::listen('login',"hello"); // x
这样才是正确的
$hello = "hello";
\Think\Hook::listen('login',$hello);//√
关于引用传递的知识这里不作介绍,请自行翻阅PHP手册。

这样我们在行为类里面run方法可以指定一个参数来接收$hello
function run($arg){
echo $arg;//输出 hello
}
当然你也可以
function run(&$arg){
echo $arg;//输出hello
$arg = "bye";
}
这样参数设定为引用类型,你可以在run里面改变原始变量的值。
Thinkphp中的_initialize
类的_initialize方法自动调用父类的_initialize方法。而php的构造函数construct,如果要调用父类的方法,必须在子类构造函数显示调用parent::__construct();

使用行为扩展时,在构造方法中使用Hook::add  添加钩子,然后就可以listen从而执行了














Thinkphp的插件机制主要依靠的是Hook.class.php这个类,官方文档中在行为扩展也主要依靠这个类来实现。下面我们来具体看看tp是怎么利用这个类来实现行为扩展的。

首先,行为扩展是什么?有wordpress二次开发经验的同学应该很容易明白,其实就是钩子,tp在其内核的执行过程中内置了诸多钩子,这些钩子可以允许我们能够在不改变内核代码的基础上来对内核进行一定程度的修改。tp的钩子机制的实现类就是Hook.class.php。

Hook.class.php内部维护了一个数组,这个数组的键就是钩子的名称,值就是类的名称的集合。我们利用Hook类的add方法可以添加一个钩子,其实就是往这个维护的数组上添加一个键值。tp默认已经定义了很多钩子标签。

app_init 应用初始化标签位
path_info PATH_INFO检测标签位
app_begin 应用开始标签位
action_name 操作方法名标签位
action_begin 控制器开始标签位
view_begin 视图输出开始标签位
view_parse 视图解析标签位
template_filter 模板内容解析标签位
view_filter 视图输出过滤标签位
view_end 视图输出结束标签位
action_end 控制器结束标签位
app_end 应用结束标签位

在3.2版本的tp框架中,钩子标签的实现机制是这样的。

首先所有的钩子标签和其对应的类是记录在应用模式文件中。tp默认的应用模式是common,对应的应用模式文件是Thinkphp/Mode/Common.php文件。在此文件中我们可以看到行为扩展的定义:

 

我们在前面说到 ThinkPHP 引导类的时候讲到此类会根据当前的模式读取模式文件并且按照模式文件中的配置依次去读取配置文件从而完成系统核心的加载。其中有一项就是上面的行为模式。在这个引导类的75行左右,程序开始加载模式文件中定义的标签和类,通过Hook::import方法把这些标签和类的映射加载到了Hook内部为的tags数组中。

然后在后面我们就可以看到tp框架在监听这些标签。何为监听?我们来看一下APP.class.php里面使用到的监听。

 

Hook::listen(‘app_begin’);就是一个监听。当程序执行到此处代码的时候,这个代码会去执行listen方法,此方法会去检测Hook持有的tags数组中是否含有app_begin标签,如果有的话就去看其对应的类文件,并到ThinkPHP\Library\Behavior目录下去寻找对应的类文件并加载实例化。然后就去调用实例化对象的run方法并执行。

由此可见,如果我们想要在应用执行开始的时候加一些我们自己的实现逻辑,只需要写一个带有run方法的行为类,这个类一般继承自Behavior类,然后在run方法中写入自己的逻辑,然后把我们写好的类名加到模式文件中,这样就可以轻松的做到扩展核心代码了。

下面我们来具体看一下Hook类的实现细节。

 



0 0
原创粉丝点击