THINKPHP钩子就是所谓的插件
项目运行时需先调用注册钩子文件:
// 应用开始
'app_begin' => [
'app\\common\\behavior\\Config', // 注册配置行为
'app\\common\\behavior\\Hook', // 注册钩子行为
],
将所有插件提前读取钩子项目插件表,将钩子数据存入\think\Hook对象中:
namespace app\common\behavior;
use app\admin\model\Hook as HookModel;
use app\admin\model\HookPlugin as HookPluginModel;
use app\admin\model\Plugin as PluginModel;
/**
* 注册钩子
* @package app\common\behavior
* @author 蔡伟明 <314013107@qq.com>
*/
class Hook
{
/**
* 执行行为 run方法是Behavior唯一的接口
* @access public
* @param mixed $params 行为参数
* @return void
*/
public function run(&$params)
{
if(defined('BIND_MODULE') && BIND_MODULE === 'install') return;
$hook_plugins = cache('hook_plugins');
$hooks = cache('hooks');
$plugins = cache('plugins');
if (!$hook_plugins) {
// 所有钩子
$hooks = HookModel::where('status', 1)->column('status', 'name');
// 所有插件
$plugins = PluginModel::where('status', 1)->column('status', 'name');
// 钩子对应的插件
$hook_plugins = HookPluginModel::where('status', 1)->order('hook,sort')->select();
// 非开发模式,缓存数据
if (config('develop_mode') == 0) {
cache('hook_plugins', $hook_plugins);
cache('hooks', $hooks);
cache('plugins', $plugins);
}
}
if ($hook_plugins) {
foreach ($hook_plugins as $value) {
if (isset($hooks[$value['hook']]) && isset($plugins[$value['plugin']])) {
\think\Hook::add($value['hook'], get_plugin_class($value['plugin']));
}
}
}
}
模版中这样调用:
{:hook('admin_index')}
调用函数在app/common.php中
if (!function_exists('hook')) {
function hook($name = '', $params = null, $extra = null, $once = false) {
\think\Hook::listen($name, $params, $extra, $once);
}
}
监听函数根据页面传递的钩子名称从对象提前存储的钩子信息中获取对应信息:
public static function listen($tag, &$params = null, $extra = null, $once = false)
{
$results = [];
foreach (static::get($tag) as $key => $name) {
$results[$key] = self::exec($name, $tag, $params, $extra);
// 如果返回 false,或者仅获取一个有效返回则中断行为执行
if (false === $results[$key] || (!is_null($results[$key]) && $once)) {
break;
}
}
return $once ? end($results) : $results;
}
然后调用执行行为函数exec执行对应方法:
public static function exec($class, $tag = '', &$params = null, $extra = null)
{
App::$debug && Debug::remark('behavior_start', 'time');
$method = Loader::parseName($tag, 1, false);
$obj = new $class();
$method = ($tag && is_callable([$obj, $method])) ? $method : 'run';
$result = $obj->$method($params, $extra);
return $result;
}
需注意执行文件中所对应的$method格式为 admin_index=>adminIndex 或者run方法
这里使用is_callable函数而不用method_exists函数是因为下面要执行该方法