thinkphp hook 怎么写

发布网友 发布时间:2022-04-23 16:56

我来回答

2个回答

懂视网 时间:2022-04-06 04:45

本文是阅读容器源码之后的最后一篇总结文章,是对容器这一知识点一个小总结

八、容器源码阅读后总结

注册模式

本文先从俩个设计模式开头,分别为单例模式和注册树模式。

单例模式简单理解就是在应用程序声明周期内只会返回一个实例对象,不会再去创建新的对象。

注册树模式理解就是会把程序中使用的对象都会存放在一颗树上,使用的时候直接从树上获取对象直接使用即可。

控制反转依赖注入

控制反转和依赖注入千万不要让名字把人虎住了,俩个看待一个事件的问题不同,一个是站在容器角度,一个是站在应用程序角度。

从容器角度来看,容器控制着应用程序,由容器反向的向应用程序注入外部资源

从应用程序的角度来看,应用程序依赖容器创建并注入它所需的外部资源。

反射

反射没有什么需要总结的,打开文档看一下就明白了,重要的要学会使用并且知道各自什么意思学会灵活运用即可。

容器源码解析

容器的源码看完后你会发现用的东西就是上边说的三个知识点形成的,运用注册模式来对容器中的对象管理。

对于这个图需要牢牢记住,在源码中就使用的这四个属性走来走去的。

在这里插入图片描述
在这里插入图片描述

在一个就是代码的执行流程

在这里插入图片描述
在这里插入图片描述

在容器中最重要的方法就是invokeClass和bindParams这俩个方法跟这咔咔的思路走就没有什么问题,跟这断点的流程一点一点执行。

这块看的时候估计有点绕,但是仔细看完之后你会发现可以学到很多东西

坚持学习、坚持写博、坚持分享是咔咔从业以来一直所秉持的信念。希望在偌大互联网中咔咔的文章能带给你一丝丝帮助。我是咔咔,下期见。

热心网友 时间:2022-04-06 01:53

ThinkPHP3.2 扩展--钩子,HOOK
之前写到TP3.1的行为扩展是tag();在TP3.2中引入了另一种说法—:钩子。

我们来看一下TP3.2中的钩子这个东西:

一:文件流程:

1:/index.php ->require './ThinkPHP/ThinkPHP.php';

2:/ThinkPHP/ThinkPHP.php—->require CORE_PATH.'Think'.EXT; Think\Think::start();

3:/ThinkPHP/Library/Think/Think.class.php—–>App::run();

4:/ThinkPHP/Library/Think/App.class.php 。到这里基本流程就走完了,(这里不说细节);

二:代码:

1:看一下 App::run()方法:

// 应用初始化标签
Hook::listen('app_init');
App::init();
// 应用开始标签
Hook::listen('app_begin');
// Session初始化
if(!IS_CLI){
session(C('SESSION_OPTIONS'));
}
// 记录应用初始化时间
G('initTime');
App::exec();
// 应用结束标签
Hook::listen('app_end');
return ;

其中的Hook::listen(”)就是用来执行钩子的,我们可以在app_init这个安插的位置用来获取应用中安装的插件。

看一下Hook::listen();

/**
* 监听标签的插件
* @param string $tag 标签名称
* @param mixed $params 传入参数
* @return void
*/
static public function listen($tag, &$params=NULL) {
if(isset(self::$tags[$tag])) {
if(APP_DEBUG) {
G($tag.'Start');
trace('[ '.$tag.' ] --START--','','INFO');
}
foreach (self::$tags[$tag] as $name) {
APP_DEBUG && G($name.'_start');
$result = self::exec($name, $tag,$params);
if(APP_DEBUG){
G($name.'_end');
trace('Run '.$name.' [ RunTime:'.G($name.'_start',$name.'_end',6).'s ]','','INFO');
}
if(false === $result) {
// 如果返回false 则中断插件执行
return ;
}
}
if(APP_DEBUG) { // 记录行为的执行日志
trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
}
}
return;
}

其中关键是:self::exec($name, $tag,$params); 看一下exec的代码:

/**
* 执行某个插件
* @param string $name 插件名称
* @param string $tag 方法名(标签名)
* @param Mixed $params 传入的参数
* @return void
*/
static public function exec($name, $tag,&$params=NULL) {
if(false === strpos($name,'\\')) {
// 插件(多个入口)
$class = "Addons\\{$name}\\{$name}Addon";
}else{
// 行为扩展(只有一个run入口方法)
$class = $name.'Behavior';
$tag = 'run';
}
$addon = new $class();
return $addon->$tag($params);
}

最后还不是 new $class();进而return $addon->$tag($params); 又转到了具体钩子的代码方法。其实就是我们原本的调用class的方法,只不过经过别人的高度封装了。

三:那么问题来了,这个钩子有什么用呢? 怎么用?

这里以OneThink 的{:hook('AdminIndex')}为例,看一些别人是怎么用的。

在系统初始化到 Hook::listen('app_init'); 时,

把app_init的标签位扩展了,在tags.php的配置文件中有这么个东西:用于初始化插件(或者说是获取系统中安装的插件)

<?php
return array(
'app_init'=>array('Common\Behavior\InitHook')
);

一看就明白,无非就是读取持久化的信息,放到缓存或是其他的方式

// 行为扩展的执行入口必须是run
public function run(&$content){
if(isset($_GET['m']) && $_GET['m'] === 'Install') return;

$data = S('hooks');
if(!$data){
$hooks = M('Hooks')->getField('name,addons');
foreach ($hooks as $key => $value) {
if($value){
$map['status'] = 1;
$names = explode(',',$value);
$map['name'] = array('IN',$names);
$data = M('Addons')->where($map)->getField('id,name');
if($data){
$addons = array_intersect($names, $data);
Hook::add($key,$addons);
}
}
}
S('hooks',Hook::get());
}else{
Hook::import($data,false);
}
}

当在程序执行到{:hook(‘AdminIndex’)}时—>调用的是Hook::listen(‘AdminIndex’);

AdminIndex这个挂载点包含了三个插件:分别是:SiteStat, SystemInfo,DevTeam。

用一个循环来分别按顺序执行.

总结:钩子其实就是起到一个挂载点的作用,这个钩子挂在哪里,就可以在哪里执行,内容或功能就是挂载插件或类库的具体实现。这样实现的代码就有很大的灵活性,挂载点不变,挂的东西变量,功能也就相应的变化,是不是很灵活强大呀。

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com