浅谈PHP中如何实现Hook机制


Posted in PHP onNovember 14, 2017

对"钩子"这个概念其实不熟悉,最近看到一个php框架中用到这种机制来扩展项目,所以大概来了解下。

所谓Hook机制,是从Windows编程中流行开的一种技术。其主要思想是提前在可能增加功能的地方埋好(预设)一个钩子,这个钩子并没有实际的意义,当我们需要重新修改或者增加这个地方的逻辑的时候,把扩展的类或者方法挂载到这个点即可。

hook插件机制的基本思想:

在项目代码中,你认为要扩展(暂时不扩展)的地方放置一个钩子函数,等需要扩展的时候,把需要实现的类和函数挂载到这个钩子上,就可以实现扩展了。

思想就是这样听起来比较笼统,看一个网上的实现的例子。

整个插件机制包含三个部分:

1.hook插件经理类:这个是核心文件,是一个应用程序全局Global对象。它主要有三个职责

    1>监听已经注册了的所有插件,并实例化这些插件对象。

    2>注册所有插件。

    3>当钩子条件满足时,触发对应的对象方法。

2.插件的功能实现:这大多由第三方开发人员完成,但需要遵循我们(经理类定义)的规则,这个规则是插件机制所规定的,因插件机制的不同而不同。

3.插件的触发:也就是钩子的触发条件。这是一小段代码,放置在你需要调用插件的地方,用于触发这个钩子。

----------------------------------看一看别人实现的方案--------------------------------

首先是插件经理类PluginManager,这个类要放在全局引用里面,在所有需要用到插件的地方,优先加载。

<?php
/**
*
* 插件机制的实现核心类

*/
class PluginManager
{
  /**
   * 监听已注册的插件
   *
   * @access private
   * @var array
   */
  private $_listeners = array();
   /**
   * 构造函数
   *
   * @access public
   * @return void
   */
  public function __construct()
  {
    #这里$plugin数组包含我们获取已经由用户激活的插件信息
   #为演示方便,我们假定$plugin中至少包含
   #$plugin = array(
    #  'name' => '插件名称',
    #  'directory'=>'插件安装目录'
    #);
    $plugins = get_active_plugins();#这个函数请自行实现
    if($plugins)
    {
      foreach($plugins as $plugin)
      {//假定每个插件文件夹中包含一个actions.php文件,它是插件的具体实现
        if (@file_exists(STPATH .'plugins/'.$plugin['directory'].'/actions.php'))
        {
          include_once(STPATH .'plugins/'.$plugin['directory'].'/actions.php');
          $class = $plugin['name'].'_actions';
          if (class_exists($class))
          {
            //初始化所有插件
            new $class($this);
          }
        }
      }
    }
    #此处做些日志记录方面的东西
  }

  /**
   * 注册需要监听的插件方法(钩子)
   *
   * @param string $hook
   * @param object $reference
   * @param string $method
   */
  function register($hook, &$reference, $method)
  {
    //获取插件要实现的方法
    $key = get_class($reference).'->'.$method;
    //将插件的引用连同方法push进监听数组中
    $this->_listeners[$hook][$key] = array(&$reference, $method);
    #此处做些日志记录方面的东西
  }
  /**
   * 触发一个钩子
   *
   * @param string $hook 钩子的名称
   * @param mixed $data 钩子的入参
   *  @return mixed
   */
  function trigger($hook, $data='')
  {
    $result = '';
    //查看要实现的钩子,是否在监听数组之中
    if (isset($this->_listeners[$hook]) && is_array($this->_listeners[$hook]) && count($this->_listeners[$hook]) > 0)
    {
      // 循环调用开始
      foreach ($this->_listeners[$hook] as $listener)
      {
        // 取出插件对象的引用和方法
        $class =& $listener[0];
        $method = $listener[1];
        if(method_exists($class,$method))
        {
          // 动态调用插件的方法
          $result .= $class->$method($data);
        }
      }
    }
    #此处做些日志记录方面的东西
    return $result;
  }
}

接下来是一个简单插件的实现DEMO_actions。这是一个简单的Hello World插件,用于输出一句话。在实际情况中,say_hello可能包括对数据库的操作,或者是其他一些特定的逻辑。

<?php
/**
* 这是一个Hello World简单插件的实现
*/
/**
*需要注意的几个默认规则:
*  1. 本插件类的文件名必须是action
*  2. 插件类的名称必须是{插件名_actions}
*/
class DEMO_actions
{
  //解析函数的参数是pluginManager的引用
  function __construct(&$pluginManager)
  {
    //注册这个插件
    //第一个参数是钩子的名称
    //第二个参数是pluginManager的引用
    //第三个是插件所执行的方法
    $pluginManager->register('demo', $this, 'say_hello');
  }

  function say_hello()
  {
    echo 'Hello World';
  }
}

再接下来就是插件的调用触发的地方,比如我要将say_hello放到我博客首页Index.php, 那么你在index.php中的某个位置写下:

$pluginManager->trigger('demo','');

第一个参数表示钩子的名字,第二个参数是插件对应方法的入口参数,由于这个例子中没有输入参数,所以为空。

这样一个例子基本上很明确的表达了"钩子"插件机制的实现方式和逻辑。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php session处理的定制
Mar 16 PHP
php 获取可变函数参数的函数
Aug 26 PHP
自己写了一个php检测文件编码的函数
Apr 21 PHP
php计算2个日期的差值函数分享
Feb 02 PHP
PHP5多态性与动态绑定介绍
Apr 03 PHP
PHP查看当前变量类型的方法
Jul 31 PHP
PHP json_encode() 函数详解及中文乱码问题
Nov 05 PHP
php 中奖概率算法实现代码
Jan 25 PHP
[原创]php token使用与验证示例【测试可用】
Aug 30 PHP
浅析PHP类的反射来实现依赖注入过程
Feb 06 PHP
layui框架实现文件上传及TP3.2.3(thinkPHP)对上传文件进行后台处理操作示例
May 12 PHP
在TP5数据库中四个字段实现无限分类的示例
Oct 18 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
Nov 14 #PHP
PHP封装的XML简单操作类完整实例
Nov 13 #PHP
PHP开发中解决并发问题的几种实现方法分析
Nov 13 #PHP
三个思路解决laravel上传文件报错:413 Request Entity Too Large问题
Nov 13 #PHP
kindeditor 加入七牛云上传的实例讲解
Nov 12 #PHP
Thinkphp5 微信公众号token验证不成功的原因及解决方法
Nov 12 #PHP
PHP 断点续传实例详解
Nov 11 #PHP
You might like
MySQL数据库转移,access,sql server 转 MySQL 的图文教程
2007/09/02 PHP
php将数据库中所有内容生成静态html文档的代码
2010/04/12 PHP
php数组函数序列之array_splice() - 在数组任意位置插入元素
2011/11/07 PHP
php常用数组array函数实例总结【赋值,拆分,合并,计算,添加,删除,查询,判断,排序】
2016/12/07 PHP
php str_replace替换指定次数的方法详解
2017/05/05 PHP
Jquery下的26个实用小技巧(jQuery tips, tricks &amp; solutions)
2010/03/01 Javascript
基于jquery的文章中所有图片width大小批量设置方法
2013/08/01 Javascript
JavaScript实现将xml转换成html table表格的方法
2015/04/17 Javascript
基于JQuery实现仿网易邮箱全屏动感滚动插件fullPage
2015/09/20 Javascript
jQuery实现响应鼠标事件的图片透明效果【附demo源码下载】
2016/06/16 Javascript
Javascript将字符串日期格式化为yyyy-mm-dd的方法
2016/10/27 Javascript
利用BootStrap的Carousel.js实现轮播图动画效果
2016/12/21 Javascript
js/jq仿window文件夹框选操作插件
2017/03/08 Javascript
jQuery插件FusionWidgets实现的AngularGauge图效果示例【附demo源码】
2017/03/23 jQuery
JS实现仿饿了么在浏览器标签页失去焦点时网页Title改变
2017/06/01 Javascript
js原生日历的实例(推荐)
2017/10/31 Javascript
vue中Element-ui 输入银行账号每四位加一个空格的实现代码
2018/09/14 Javascript
基于Vue实现电商SKU组合算法问题
2019/05/29 Javascript
非常漂亮的js烟花效果
2020/03/10 Javascript
微信小程序仿抖音视频之整屏上下切换功能的实现代码
2020/05/24 Javascript
解决Vue keep-alive 调用 $destory() 页面不再被缓存的情况
2020/10/30 Javascript
Vuex实现简单购物车
2021/01/10 Vue.js
用Python程序抓取网页的HTML信息的一个小实例
2015/05/02 Python
python+selenium开发环境搭建图文教程
2017/08/11 Python
python中如何正确使用正则表达式的详细模式(Verbose mode expression)
2017/11/08 Python
python自动发送邮件脚本
2018/06/20 Python
Python3多目标赋值及共享引用注意事项
2019/05/27 Python
Python接口测试get请求过程详解
2020/02/28 Python
如何通过Python实现RabbitMQ延迟队列
2020/11/28 Python
Html5基于canvas实现电子签名并生成PDF文档
2020/12/07 HTML / CSS
澳洲国民品牌乡村路折扣店:Country Road & Trenery Outlet
2018/04/19 全球购物
学校十一活动方案
2014/02/01 职场文书
煤矿机修工岗位职责
2014/02/07 职场文书
会计专业求职信
2014/08/10 职场文书
2014新生大学四年计划书
2014/09/21 职场文书
人身损害赔偿协议书范本
2014/09/27 职场文书