视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
ThinkPHP3.2扩展
2020-11-09 15:25:20 责编:小采
文档

之前写到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:

之前写到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 @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 @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'); 时,

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。
用一个循环来分别按顺序执行.

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


以上只属于学习笔记,若有错请指正。

下载本文
显示全文
专题