php ghook 全局钩子功能 v0

来源:互联网 发布:2017淘宝美工工资待遇 编辑:程序博客网 时间:2024/05/22 15:25
在 cms 系统中遇到过这种情况:
其它模块的数据需要关联会员模块的会员数据,所以在删除会员时应需要与会员数据关联的模块进行数据关联操作。
比如删除一个会员时同时删除此会员发布的文章。
但是,其它模块是在会员模块之后才开发出来的,要实现这种关联性,可以每多一个与会员模块关联的模块就改动一次会员模块的代码,又或者,使用 hook(钩子)的概念。

通过制定一套全系统模块统一的 hook 规则,令数据关联问题通过 hook 灵活地解决。
值得注意,这套 hook 规则首要解决的是模块间的数据关联问题,其次才考虑实现模块“插件”那种 hook 。

下面以“删除一个会员数据应先删除其相关数据”为例子说明这套 hook 规则:

在模块目录使用 hook 目录保存与 hook 系统相关的所有代码。
/member/hook/ 是会员模块 hook 目录。
/comment/hook/ 是评论模块 hook 目录。

在这个例子中, hook 是由会员模块提供的,如“删除一个会员”hook。其它模块挂载到会员模块的 hook 中。
提供及挂载 hook 的代码使用类的形式定义,钩子使用 hook 这个单词,挂载的代码使用 callback 这个单词。

在 hook 目录内使用一个名为 mod 的文本文件记录挂载到此模块的模块列表,一行一个:
file:/member/hook/mod
comment

提供 hook 的类使用 h_ 前序(h表示hook),文件名规则为 h_{hook_name}.class.php ,对应的类名为 h_{mod_name}_{hook_name} 。
类中的方法就是一个个 hook 。方法的调用参数就是 hook 的调用参数。
file:/member/hook/h_base.class.php

对应的类名为 h_member_base 。

class h_member_base{/*** 删除一个用户的 hook*/function delete_one($userid){// 调用挂载模块的同名方法。}}

挂载的模块在自己的 hook 目录下定义 callback 类,使用 hc_ 前序(h表示hook,c表示callback),文件名命名规则为:hc_{mod_name}_{hook_name}.class.php 。mod_name 为所挂载模块的模块名,hook_name 为所挂载的 hook 类的名称。
对应的 callback 类名为 hc_{self_mod_name}_{mod_name}_{hook_name} ,{self_mod_name} 为本模块名称:
file:/comment/hook/hc_member_base.class.php

对应的类名为 hc_comment_member_base 。

class hc_comment_member_base{/*** 处理删除一个用户的 callback 方法。*/function delete_one($userid){// 删除对应用户的相关数据。}}


hook 和 callback 类的加载与实例化,由 ghook 类负责, ghook 类所有方法为静态方法,且禁止实例化。

放出 hook 的模块在代码的相关位置使用 ghook::call() 方法调用 hook 。
函数原型为:
object call($mod_name, $hook_name)
$mod_name : 放出 hook 的模块名 eg. member
$hook_name : hook 类名称 eg. base
此方法会加载并实例化 $mod_name 模块的 $hook_name hook 类,并返回 hook 类对像的引用,可直接调用 hook 类对应的方法。
比如在 member 模块删除一个会员的代码处调用:
ghook::call('member', 'base')->delete_one($userid);

在 hook 类中使用 ghook::load() 方法加载所有挂载模块的 callback 类并实例化。
函数原型为:
array load($mod_name, $hook_class_name, $method_name)
$mod_name : hook 类所在模块。
$hook_class_name : hook 类名。
$method_name : 对应方法名。

此方法会把所有符合条件的 callback 类实例以数组形式返回,只需要循环并调用方法即可:

class h_member_base{/*** 删除一个用户的 hook*/function delete_one($userid){$list = ghook::load('member', __CLASS__, __FUNCTION__);foreach ($list as $obj){$obj->delete_one($userid); // ghook 保证返回的对象一定有 delete_one 方法可被调用。}return true}}

以下是 ghook 设计好但未实现的方法:

ghook::reg(callback, mod_name, __CLASS__[, __FUNCTION__])
把一个(对像|对像的方法|函数)注册到对应的 hook 上,用于临时注册。

把 hook 相关代码集中在 hook 目录,方便查阅与管理。
使用类型式,比使用函数型式更灵活与方便,能方便地对各类 hook 进行分组,一个类中的方法就是一组,比如删除会员有单个删除,批量删除等,就可以放在命名为 delete 的 hook 类中。
一个模块所有 hook 都在 hook/ 目录中,定义与调用分开。令查阅直观又方便,方法的说明及参数就是 hook 的说明,无需另外建立文档说明模块的 hook 信息。(与 wordpress 不同,wordpress 的 hook 是散落于各处源代码中)
在 hook 类的方法中调用 callback 类的方法,能让各种 hook 灵活地自定义 hook 的输入输出,参数形式,返回值,处理流程等等的一切。(这与 wordpress 也不同, wordpress 接管了所有钩子的调用形式,因此在参数传递,处理流程,返回值等上都有很大的限制)