hook编程机制(php实现)

hook编程机制(php实现)hook 编程机制 php 实现 最近业余时间自己写框架玩 有用到 hook 百度了网上的 hook 博客 发现全网基本上都是几篇博客转来转去 且有些地方写的比较模糊 打算自己利用一个小小的用例完善总结一下自己理解的 hook 方便网友 巩固自己 说明 hook 中文翻译为钩子 编程中的钩子类似我们现实中的钩子 需要挂在东西的时候直接挂载到上面即可 程序中也是 需要运行的代码挂载到上面即可

hook编程机制(php实现)

最近业余时间自己写框架玩,有用到hook。百度了网上的hook博客,发现全网基本上 都是几篇博客转来转去,且有些地方写的比较模糊。打算自己利用一个小小的用例 完善总结一下自己理解的hook,方便网友,巩固自己。

说明

hook,中文翻译为钩子,编程中的钩子类似我们现实中的钩子,需要挂在东西的时候 直接挂载到上面即可。程序中也是,需要运行的代码挂载到上面即可。 具体思想就是:在项目代码中,你认为要扩展(暂时不扩展)的地方放置一个钩子函数, 等需要扩展的时候,把需要实现的类和函数挂载到这个钩子上,就可以实现扩展了。

实例

1,需求背景

1,产品刚开始提了一个需求,很简单,就是获取一个一维数组,再将数组打印出来

代码如下实现即可 
  get_arr(); //打印数组 $this->print_arr($arr); } public function get_arr() { $arr = [9,5,6,0,1,4,7,34,67,28,105,278]; return $arr; } public function print_arr($arr) { echo "
"; print_r($arr); } } $printArrObj = new printArr; $printArrObj->main();

2,好吧,功能完成后,产品觉得这样输出不太好,最好是有序输出。熟悉冒泡排序的你,赶紧对代码做了如下调整(如下虚线内代码)

 
  get_arr(); //---------------------------------------------------- $arr = $this->bubble_sort($arr); //---------------------------------------------------- //打印数组 $this->print_arr($arr); } public function get_arr() { $arr = [9,5,6,0,1,4,7,34,67,28,105,278]; return $arr; } public function print_arr($arr) { echo "
"; print_r($arr); } //---------------------------------------------------- public function bubble_sort($arr) { //自行完成 } //---------------------------------------------------- } $printArrObj = new printArr; $printArrObj->main();

3,好吧,你的功能完成了。但是后来数据量变大了,产品说冒泡排序运行效率太低,让你用插入排序法排序。

你怕无理的产品后面又换回冒泡,于是注释掉冒泡,又写了插入排序法 
  get_arr(); //---------------------------------------------------- //$arr = $this->bubble_sort($arr); $arr = $this->insert_sort($arr); //---------------------------------------------------- //打印数组 $this->print_arr($arr); } public function get_arr() { $arr = [9,5,6,0,1,4,7,34,67,28,105,278]; return $arr; } public function print_arr($arr) { echo "
"; print_r($arr); } //---------------------------------------------------- /*public function bubble_sort($arr) { //自行完成 }*/ public function insert_sort($arr) { //自行完成 } //---------------------------------------------------- }

4,嗯,后面项目越来越复杂,产品越来越变态。说4,这个数字不好,数组中带4的unset掉。和上面代码一样,你又写了一个方法,夹在数组的获取和输出的中间,用来unset掉4这个数字。

好吧,对你来说就价格方法而已,那就加呗 
  get_arr(); //---------------------------------------------------- //$arr = $this->bubble_sort($arr); $arr = $this->insert_sort($arr); $arr = $this->unset_4($arr); //---------------------------------------------------- //打印数组 $this->print_arr($arr); } public function get_arr() { $arr = [9,5,6,0,1,4,7,34,67,28,105,278]; return $arr; } public function print_arr($arr) { echo "
"; print_r($arr); } //---------------------------------------------------- /*public function bubble_sort($arr) { //自行完成 }*/ public function insert_sort($arr) { //自行完成 } public function unset_4($arr) { //自行完成 } //---------------------------------------------------- }

5,这个产品越来越变态,说3不好,也要unset掉,5不好也要unset掉。8这个数字好,给数组中加个8,又说666这个数字更好,要加个666。并且半个小时要做完。你终于受不了了,提议你一个人做不完。产品经理二话不说调来好几个人,每人做一个。

1,这里就要说出现的问题了。每个工程师的习惯都不一样 比如你封装了方法,写在了输出数组这个主类的下面,main函数中直接调用了 小王同事不喜欢封装方法,直接在获取数组和打印数组之间添加了代码段。 小李同事觉得输出数组当前这个类,为主类,处理过程自己封装一个副类,副类中封装方法,在输出数组这个类引入调用即可。 等等等等方案。 2,然后产品更多的变态需求出来了,你们团队也默默的维护着输出数组中间的每一道工序。就这样不知不觉两年过去了, 突然线上出现了一个小bug,你作为技术大牛,排错交给了你, 接下来你开始排错 封装方法的工程师,写了500多个方法在下面,虽然难找不过耐心点还可以慢慢找到维护排错。 封装副类的工程师,封装了100多个副类,各类下都有各种方法,再耐心点吧,慢慢找还可以维护排错。 直接加代码段的工程师,两年积累了五六千行代码,好吧,你需要读懂每一行才能发现问题, 到了这个时候,我猜你直接想骂娘了吧,气冲冲的找来加代码段的工程师,让他看看这段代码 什么意思,结果呢,两年前的代码,他自己都不知道什么意思了,这下完了,你是不是心态崩 了,你是不是绝望了,你是不是直接想离职了?

6,现在想想,你们公司内部两年积累的代码已经能让你到了崩溃的边缘,那如果开源代码,天下人都能维护,并且维护了十多年,如果按照上面维护的路子来维护,那这个开源软件早都嗝屁了吧。

故事讲到这里,就到此为止。hook编程机制就是解决此类问题应运而生的。

2,解决方案

对,解决上面的问题,从三个方向入手。 1,对应产品提出不同需求改动,用插件的形式整齐划一的放在对应插件库里。 2,插件管理类,用来注册插件,监听插件是否需要运行,需要的直接hook过来,运行即可。 3,在获取数组和输出数组中间放一段插件触发器,用来触发需要运行的插件。 以上也就是插件的三要素。

3,示例代码

按照hook原理做一个简单的插件用例 结构:hookDemo |-----index.php//主运行代码,触发器hook放在可能需要利用插件的地方 |-----pluginManager.php//插件管理类 |-----plugin//插件目录 |------sort.php//插件 |------unsetElement.php//插件

index.php

 
  pluginManagerObj = new pluginManager(); } public function main() { //获取数组 $arr = $this->get_arr(); //hook,也就是触发函数 $arr = $this->pluginManagerObj->trigger('unsetElement',$arr); $arr = $this->pluginManagerObj->trigger('sort',$arr); $this->print_arr($arr); //输出数组 } public function get_arr() { $arr = [9,5,6,0,1,4,7,34,67,28,105,278]; return $arr; } public function print_arr($arr) { echo "
"; print_r($arr); } } echo "
"; $printArrObj = new printArr; $printArrObj->main();

pluginManager.php

 
  $v){ if($v == '.' || $v == '..'){ unset($plugin_list[$k]); } } if($plugin_list){ foreach($plugin_list as $v){ if(file_exists('./plugin/'.$v)){ //引入插件 require_once('./plugin/'.$v); //获取插件名 $class = explode('.',$v); $class = $class[0]; if(class_exists($class)){ new $class($this); } } } } } //注册插件 public function register($hook,&$obj,$method) { $key = get_class($obj).'->'.$method; $val = [$obj,$method]; $this->listen[$hook][$key] = $val; } //触发插件 public function trigger($hook,$data) { if(isset($this->listen[$hook]) && is_array($this->listen[$hook]) && count($this->listen[$hook])>0){ foreach($this->listen[$hook] as $key => $val){ $hook_obj = &$val[0]; $method = $val[1]; $res = $hook_obj->$method($data); } } return $res; } }

sort.php

 
  register('sort',$this,'sort'); } public function sort($arr) { for($i=1;$i 
  
    =0;$j--){ if($arr[$j+1] > $arr[$j]){ $tmp = $arr[$j]; $arr[$j] = $arr[$j+1]; $arr[$j+1] = $tmp; }else{ break; } } } return $arr; } } 
  

unsetElement.php

 
  register('unsetElement',$this,'unset_4'); } public function unset_4($arr) { foreach($arr as $k=>$v){ if($v == 4){ unset($arr[$k]); } } return array_values($arr); } }

心得

1,关于hook

结合上面的例子,hook最好的方面是,插件和项目互相独立,降低耦合性。第三方开发人员也不 需要知道项目如何处理,类似api一样,只需要知道插件需求即可开发。 二来,插件跟核心代码分离,方便各个区间段排错 三来,项目开发过程中,防止了代码的冗余杂乱,更适用于开源项目

2,关于实现

三要素, 触发函数,plugin管理类,plugin代码。 实现过程中, 插件管理类和插件类实例化的对象必须贯穿全局且唯一。因为注册和执行过程中,监听信息 要保持全局。实现方案有三种: 1,对象的各种操作必须用引用&。 2,用单例模式获取对象 3,$_GLOBAL; 上面的例子只是一个简单的说明, 熟悉原理后,可以拓展设置plugin配置文件对plugin管理, 对plugin本身做到互相联系,互相调用。具体拓展情况按照需求而定 hook思路理解清楚后,不拘泥于我上面写的这种方式,因为这种方式只是自己写框架玩的时候 利用了面向对象方式。 总之hook最广泛的原理,就是 开局注册全局监听变量, 全局监听变量负责监听, 触发函数负责触发, 一旦触发执行代码
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/212099.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午8:50
下一篇 2026年3月18日 下午8:50


相关推荐

  • tcpdump抓包命令怎么用_tcpdump指定ip抓包命令

    tcpdump抓包命令怎么用_tcpdump指定ip抓包命令今天要给大家介绍的一个Unix下的一个网络数据采集分析工具,也就是我们常说的抓包工具。与它功能类似的工具有wireshark,不同的是,wireshark有图形化界面,而tcpdump则只有命令行。由于我本人更习惯使用命令行的方式进行抓包,因此今天先跳过wireshark,直接给大家介绍这个tcpdump神器。这篇文章,我肝了好几天,借助于Linux的man帮助命令,我把tcpdump的用法全部研究了个遍,才形成了本文,不夸张的说,应该可以算是中文里把tcpdump.

    2022年8月20日
    21
  • Eclipse深度患者设置VSCode快捷键「建议收藏」

    Eclipse深度患者设置VSCode快捷键「建议收藏」VSCode设置Eclipse中常用的快捷键将eclipse中一些基本的快捷键输入右侧用户快捷键设置中://Placeyourkeybindingsinthisfiletooverwritethedefaults[{"key":"alt+/","command":"editor.action.triggerSuggest","when":…

    2022年5月27日
    78
  • vue子组件给父组件传值

    vue子组件给父组件传值子组件:<template>  <divclass="app">    <input@click="sendMsg"type="button"value="给父组件传递值">  </div></template><script&gt

    2022年6月6日
    33
  • 使用递归实现买汽水(华为面试题)

    今天老范问了我一个问题问题:一个人买汽水,一块钱一瓶汽水,三个瓶盖可以换一瓶汽水,两个空瓶可以换一瓶汽水问20块钱可以买多少汽水?注意:使用递归这一题乍一看,哎哟,这么简单,能买几瓶?恩。。五瓶!为啥啊?多了我喝不完啊!老范说,喝不完关你屁事,又不是给你喝哦哦哦,那没事儿了,我想想。在知道自己的人生安全得到了保障之后,我冷静下来仔细思考了如何用递归实现这个问题

    2022年4月9日
    59
  • C语言二维数组作为函数参数传递

    C语言二维数组作为函数参数传递二维数组存放方式二维数组在内存中是按行存放的 先存储第一行 在接着存储第二行 二维数组作为函数参数二维数组作为函数的参数 实参可以直接使用二维数组名 在被调用函数中可以定义形参所有维数的大小 也可以省略以为大小的说明 例如 voidfind chara 3 10 voidfind chara 10 也可以使用数组指针来作为函数参数 例如

    2026年3月18日
    2
  • 插件MyBatisCodeHelperPro的激活(简单方法)

    插件MyBatisCodeHelperPro的激活(简单方法)目录一 前言二 安装插件 MyBatisCodeH 插件三 激活一 前言在开发中编写生成 bean mapper mapper xml 即费时也费力 可以通过 MyBatisCodeH 自动生成 bean dao mapper xml 等文件 然后根据自己的需要进行修改 MyBatisCodeH 是 IDEA 下的一个插件 类似于 mybatisplugi 但是是收费的 但可以进行激活使用 下面这个大佬的个人主页上有多个版本的下载链

    2026年3月19日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号