php扩展实现hook,ThinkPHP3.2 扩展(钩子,HOOK)

本文详细探讨ThinkPHP框架中的插件执行流程,通过Hook::listen()函数实现动态扩展功能,如OneThink框架中的AdminIndex钩子加载多个插件。理解钩子如何作为功能挂载点,增强程序灵活性。
摘要由CSDN通过智能技术生成

Thinkphp 执行流程

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

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

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

/ThinkPHP/Library/Think/App.class.php

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这个安插的位置用来获取应用中安装的插件

/**

* 监听标签的插件

* @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的配置文件中有这么个东西:用于初始化插件(或者说是获取系统中安装的插件)

return array(

'app_init'=>array('Common\Behavior\InitHook')

);

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);

}

}

onethink_hooks 表结构

DROP TABLE IF EXISTS `onethink_hooks`;

CREATE TABLE `onethink_hooks` (

`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',

`name` varchar(40) NOT NULL DEFAULT '' COMMENT '钩子名称',

`description` text NULL COMMENT '描述',

`type` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '类型',

`update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',

`addons` varchar(255) NOT NULL DEFAULT '' COMMENT '钩子挂载的插件 '',''分割',

`status` tinyint(1) unsigned NOT NULL DEFAULT '1',

PRIMARY KEY (`id`),

UNIQUE KEY `name` (`name`)

) ENGINE=MyISAM DEFAULT CHARSET=utf8;

-- -----------------------------

-- Records of `onethink_hooks`

-- -----------------------------

INSERT INTO `onethink_hooks` VALUES ('13', 'AdminIndex', '首页小格子个性化显示', '1', '1382596073', 'SiteStat,SystemInfo,DevTeam', '1');

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

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值