php hook编程机制
说明
hook,中文翻译为钩子,编程中的钩子类似我们现实中的钩子,需要挂在东西的时候
直接挂载到上面即可。程序中也是,需要运行的代码挂载到上面即可。
具体思想就是:在项目代码中,你认为要扩展(暂时不扩展)的地方放置一个钩子函数,
等需要扩展的时候,把需要实现的类和函数挂载到这个钩子上,就可以实现扩展了。
实例
1,需求背景
1,产品刚开始提了一个需求,很简单,就是获取一个一维数组,再将数组打印出来
代码如下实现即可
<?php
class printArr
{
public function main()
{
//获取数组
$arr = $this->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 "<pre>";
print_r($arr);
}
}
$printArrObj = new printArr;
$printArrObj->main();
2,好吧,功能完成后,产品觉得这样输出不太好,最好是有序输出。熟悉冒泡排序的你,赶紧对代码做了如下调整(如下虚线内代码)
<?php
class printArr
{
public function main()
{
//获取数组
$arr = $this->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 "<pre>";
print_r($arr);
}
//----------------------------------------------------
public function bubble_sort($arr)
{
//自行完成
}
//----------------------------------------------------
}
$printArrObj = new printArr;
$printArrObj->main();
3,好吧,你的功能完成了。但是后来数据量变大了,产品说冒泡排序运行效率太低,让你用插入排序法排序。
你怕无理的产品后面又换回冒泡,于是注释掉冒泡,又写了插入排序法
<?php
class printArr
{
public function main()
{
//获取数组
$arr = $this->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 "<pre>";
print_r($arr);
}
//----------------------------------------------------
/*public function bubble_sort($arr)
{
//自行完成
}*/
public function insert_sort($arr)
{
//自行完成
}
//----------------------------------------------------
}
4,嗯,后面项目越来越复杂,产品越来越变态。说4,这个数字不好,数组中带4的unset掉。和上面代码一样,你又写了一个方法,夹在数组的获取和输出的中间,用来unset掉4这个数字。
好吧,对你来说就价格方法而已,那就加呗
<?php
class printArr
{
public function main()
{
//获取数组
$arr = $this->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 "<pre>";
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
<?php
class printArr
{
public $pluginManagerObj;
public function __construct()
{
//凡事用到hook的类,优先加载hook类
require './pluginManager.php';
$this->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 "<pre>";
print_r($arr);
}
}
echo "<pre>";
$printArrObj = new printArr;
$printArrObj->main();
pluginManager.php
<?php
class pluginManager
{
//监听数组
public $listen = [];
public function __construct()
{
//构造方法,引入插件以及监听
$plugin_list = scandir('./plugin');
foreach($plugin_list as $k=>$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
<?php
class sort
{
public function __construct(&$pluginManagerObj)
{
$pluginManagerObj->register('sort',$this,'sort');
}
public function sort($arr)
{
for($i=1;$i<count($arr);$i++){
for($j=$i-1;$j>=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
<?php
class unsetElement
{
public function __construct(&$pluginManagerObj)
{
$pluginManagerObj->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最广泛的原理,就是
开局注册全局监听变量,
全局监听变量负责监听,
触发函数负责触发,
一旦触发执行代码
---------------------
作者:敦煌的驼铃
来源:CSDN
原文:https://blog.csdn.net/SiuKong_Ngau/article/details/83587048
版权声明:本文为博主原创文章,转载请附上博文链接!
php hook编程机制的更多相关文章
- php中的钩子(hook插件机制)
对"钩子"这个概念其实不熟悉,最近看到一个php框架中用到这种机制来扩展项目,所以大概来了解下. hook插件机制的基本思想: 在项目代码中,你认为要扩展(暂时不扩展)的地方放置一 ...
- 阿里系产品Xposed Hook检测机制原理分析
阿里系产品Xposed Hook检测机制原理分析 导语: 在逆向分析android App过程中,我们时常用的用的Java层hook框架就是Xposed Hook框架了.一些应用程序厂商为了保护自家a ...
- MFC中的HOOK编程
HOOK,n.钩, 吊钩,通常称钩子. 在计算机中,是Windows消息处理机制的一个平台,应用程序能够在上面设置子程以监视指定窗体的某种消息,并且所监视的窗体能够是其它进程所创建的.当消息到达后,在 ...
- 钩子(hook)编程
一.钩子介绍 1.1钩子的实现机制 钩子英文名叫Hook,是一种截获windows系统中某应用程序或者所有进程的消息的一种技术.下图是windows应用程序传递消息的过程: 如在键盘中按下一键,操作系 ...
- adbi学习:java hook实现机制
adbi的java hook实现代码ddi不在之前下载的文件中,下载地址:https://github.com/crmulliner/ddi,具体的编译看readme里面很详细的介绍了.注意ddi代码 ...
- 孙鑫MFC学习笔记20:Hook编程
1.HOOK拦截消息,设置越后的钩子优先级越高(钩子队列)2.SetWindowHookEx设置钩子 如果thread identifier为0或其他进程创建的线程,回调函数需要在动态链接库中声 ...
- 01-.Net编程机制
.NetFarmwark特点: 多平台:该系统可以在广泛的计算机上运行,包括从服务器.桌面机到PDA和移动电话. 行业标准:该系统使用行业标准的通信协议,比如XML.HTTP.SOAP和WSDL. 安 ...
- adbi学习:so hook实现机制
本篇我们来看看adbi的实现原理,其实里面的知识点前面差不多都有涉及了,没多少新知识.adbi利用hijack程序将libexample.so注入到指定的进程中,并且在进程中加载libexample. ...
- 【windows核心编程】系统消息与自定义钩子(Hook)使用
一.HOOk Hook是程序设计中最为灵活多变的技巧之一,在windows下,Hook有两种含义: 1.系统提供的消息Hook机制 2.自定义的Hook编程技巧 其中,由系统提供的消息钩子机制是由一系 ...
随机推荐
- 20175236 《Java程序设计》实验一(Java开发环境的熟悉)实验报告
一.实验报告封面 课程:Java程序设计 班级:1752班 姓名:温丰帆 学号:20175236 指导教师:娄嘉鹏 实验日期:2019年4月2日 实验时间:13:45 - 15:25 实验序号:实验一 ...
- Redis深入学习笔记(一)Redis启动数据加载流程
这两年使用Redis从单节点到主备,从主备到一主多从,再到现在使用集群,碰到很多坑,所以决定深入学习下Redis工作原理并予以记录. 本系列主要记录了Redis工作原理的一些要点,当然配置搭建和使用这 ...
- Apache的ServerAlias的作用
今天在php的集成环境laragon上添加了一个虚拟主机,域名为:whathell.com 突然想在前面加个www. 一种做法是在auto.whathell.com文件中添加如下内容: <Vir ...
- php sleep函数延迟执行
PHP sleep函数一般用于定时执行任务中,表示延迟多少秒在执行程序.这里主机吧主要给大家讲一下sleep函数的语法和应用实例. sleep函数语法: sleep(seconds); //secon ...
- CentOS 7修改系统时间及硬件时间
转载于:https://www.cnblogs.com/LouisZJ/p/8554991.html [root@nginx ~]# timedatectl --help timedatectl [O ...
- Java ---- 链表逆序
public class LinkedListRevert { public static void main(String[] args) { Node next3 = new Node(4,nul ...
- this 的指向
使用 JavaScript 开发的时候,很多开发者多多少少会被 this 的指向搞蒙圈,但是实际上,关于 this 的指向,记住最核心的一句话:哪个对象调用函数,函数里面的this指向哪个对象. 下面 ...
- (20/24) webpack实战技巧:watch实现热打包和添加代码备注
在前面的学习中,我们一直使用webpack-dev-server充当(本地)服务器和完成打包任务,但是当出项目团队联合开发,共同使用一个服务器时,这时候我们需要实时进行打包以确保团队间能进行联调或者进 ...
- MongoDB基础入门
1,安装 下载解压安装包 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.5.tgz tar -xvzf mongodb- ...
- 模仿input闪烁光标
模仿闪烁的光标 <span class="cursor-blink"> </span> 样式代码: .cursor-blink { display: inl ...