TP框架的钩子功能很早就有了,tp5.1对它的实现又重新构造了,钩子的功能其实就是在代码中侵入其他代码流程。比如在初始化完后监听一个钩子,如果我们注册了这个钩子,并且绑定了一个行为,执行到这里的时候会执行我们绑定的行为。
创建行为类,不用继承任何类
namespace app\http\behavior;
class ActionBegin
{
public function run($params)
{
echo 'ActionBegin';
}
}
配置行为和钩子,在各个模块目录下建一个tag.php文件即可,配置内容只会在对应的模块生效。例如application/tag.php,会对所有模块生效。如果在application/admin/tag.php,则只会对admin模块生效。
// 应用行为扩展定义文件
return [
// 应用初始化
'app_init' => [],
// 应用开始
'app_begin' => [
'app\http\behavior\LogBegin'
],
// 模块初始化
'module_init' => [],
// 操作开始执行
'action_begin' => [
'app\http\behavior\ActionBegin'
],
// 视图内容过滤
'view_filter' => [],
// 日志写入
'log_write' => [],
// 应用结束
'app_end' => [],
];
$tags=[],钩子行为定义,不同的钩子对应哪些行为。
static $portal = 'run',表示行为的入口方法。默认是run,所有我们定义行为的时候,要有run方法。
add($tag, $behavior, $first = false),tag是钩子名称,$behavior是行为类名,通过这个方法,把钩子和行为加入到$tags属性中。
listen($tag, $params = null, $once = false),监听钩子,会通过$tag参数去$this->tags属性找对应的行为。如果发现有对应的行为类,就会调用execTag($class, $tag = '', $params = null)去执行这个行为。
在模块初始化阶段init(),会把tag.php的配置加入到Hook的属性tags中。
// 加载行为扩展文件
if (is_file($path . 'tags.php')) {
$tags = include $path . 'tags.php';
if (is_array($tags)) {
$this->hook->import($tags);
}
}
在不同的阶段监听不同的钩子
// 监听app_init
$this->hook->listen('app_init');
tp框架为我们监听了很多个钩子,我们可以直接利用。如果想自定义钩子,可以手动用Hook类的add()注册钩子行为,然后再合适的地方Listen钩子即可。
新版的事件系统可以看成是5.1
版本行为系统的升级版,事件系统相比行为系统强大的地方在于事件本身可以是一个类,并且可以更好的支持事件订阅者。事件相比较中间件的优势是事件比中间件更加精准定位(或者说粒度更细),并且更适合一些业务场景的扩展。很多原来的钩子都废弃了,因为有些钩子可以直接用中间件来实现。
一般我们不用定义事件,框架已经定义好了几个事件
事件 | 描述 | 参数 |
---|---|---|
AppInit | 应用初始化标签位 | 无 |
HttpRun | 应用开始标签位 | 无 |
HttpEnd | 应用结束标签位 | 当前响应对象实例 |
LogWrite | 日志write方法标签位 | 当前写入的日志信息 |
RouteLoaded | 路由加载完成 | 无 |
要监听事件,首先定义好事件监听器
命令php think make:listener AppInit默认会生成一个app\listener\AppInit
事件监听类,实现handle方法即可。
在event.php下配置,可以配置多个监听类。只要调用了$event->listen('AppInit'),就会执行监听器的handle方法。
return [
'listen' => [
'AppInit' => [
'app\listener\AppInit',
]
],
];
命令php think make:subscribe User默认会生成app\subscribe\User
类,或者你可以指定完整类名生成
User类通过on+事件名作为方法,可以对不同的事件进行监听
class User
{
public function onAppInit()
{
echo 'subscribe appinit';
}
public function onRouteLoaded()
{
echo 'subscribe routeload';
}
}
'subscribe' => [
'app\subscribe\User'
],
我们代码中也可以是用Event类来创建事件,然后监听事件,处理事件,这个就是观察者模式编程。当主题对象触发发生变化(触发事件),多个观察者(定义好的监听器)就会执行对应的方法。 一个对象和多个对象的关系的时候用观察者模式。
重要属性:
$bind:事件别名,['别名'=>'类名'];
$listener:监听者