PHP中的插件机制原理和实例


Posted in PHP onJuly 08, 2014

PHP项目中很多用到插件的地方,更尤其是基础程序写成之后很多功能由第三方完善开发的时候,更能用到插件机制,现在说一下插件的实现。特点是无论你是否激活,都不影响主程序的运行,即使是删除也不会影响。

从一个插件安装到运行过程的角度来说,主要是三个步骤:

1.插件安装(把插件信息收集进行采集和记忆的过程,比如放到数据库中或者XML中)

2.插件激活(打开插件,让监听插件的地方开始进行调用)

3.插件运行(插件功能的实现)

从一个插件的运行上来说主要以下几点:

1.插件的动态监听和加载(插件的信息获取)

2.插件的动态触发(插件的运行)

一个完善的插件系统主要包括以下:

1.插件安装及卸载

2.插件打开与关闭

3.插件信息获取

4.插件调度(插件经理)

5.插件主体

在程序的编写上主要实现以下:

1.插件的注册和初始化

2.判断激活条件

3.钩子激活

4.运行插件

实例代码:

<?php
/** 
* PluginManager Class 
* 
* 插件机制的实现核心类 
* 
* @link https://3water.com/ 
*/ 
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();#这个函数请自行实现 
 
    //函数实现后的最终数据结构效果如下
    $plugins=array(array("directory"=>"demo",
    "name"=>"DEMO"));
 
 
    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)) 
          { 
            //初始化所有插件 
            //$this 是本类的引用
            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; 
  } 
} 
 
define(STPATH, "./");
 
$pluginManager=new PluginManager();
 
$pluginManager->trigger("demo");

demo插件文件:

<?php
/**
 * 这是一个Hello World简单插件的实现
 *
 * @link    https://3water.com/
 */
/**
 *需要注意的几个默认规则:
 *  1. 本插件类的文件名必须是action
 *  2. 插件类的名称必须是{插件名_actions}
 */
class DEMO_actions
{
  //解析函数的参数是pluginManager的引用
  function __construct(&$pluginManager)
  {
    //注册这个插件
    //第一个参数是钩子的名称
    //第二个参数是pluginManager的引用
    //第三个是插件所执行的方法
    $pluginManager->register('demo', $this, 'say_hello');
  }
 
  function say_hello()
  {
    echo 'Hello World';
  }
}
PHP 相关文章推荐
Email+URL的判断和自动转换函数
Oct 09 PHP
PHP 加密/解密函数 dencrypt(动态密文,带压缩功能,支持中文)
Jan 30 PHP
PHP反转字符串函数strrev()函数的用法
Feb 04 PHP
PHP中isset()和unset()函数的用法小结
Mar 11 PHP
ThinkPHP实现支付宝接口功能实例
Dec 02 PHP
php的4种常见运行方式
Mar 20 PHP
WordPress中查询文章的循环Loop结构及用法分析
Dec 17 PHP
利用php做服务器和web前端的界面进行交互
Oct 31 PHP
PHP实现移除数组中为空或为某值元素的方法
Jan 07 PHP
PHP5.5安装PHPRedis扩展及连接测试方法
Jan 22 PHP
thinkPHP5项目中实现QQ第三方登录功能
Oct 20 PHP
Laravel配合jwt使用的方法实例
Oct 25 PHP
phpmailer在服务器上不能正常发送邮件的解决办法
Jul 08 #PHP
php去掉URL网址中带有PHPSESSID的配置方法
Jul 08 #PHP
PHP大批量插入数据库的3种方法和速度对比
Jul 08 #PHP
php发送get、post请求的6种方法简明总结
Jul 08 #PHP
PHP中对各种加密算法、Hash算法的速度测试对比代码
Jul 08 #PHP
微信公众平台天气预报功能开发
Jul 06 #PHP
最常用的8款PHP调试工具
Jul 06 #PHP
You might like
最简单的PHP程序--记数器
2006/10/09 PHP
php生成随机密码的三种方法小结
2010/09/04 PHP
LotusPhp笔记之:Cookie组件的使用详解
2013/05/06 PHP
解析isset与is_null的区别
2013/08/09 PHP
php析构函数的简单使用说明
2015/08/24 PHP
静态html文件执行php语句的方法(推荐)
2016/11/21 PHP
ThinkPHP5.1+Ajax实现的无刷新分页功能示例
2020/02/10 PHP
CSS心形加载的动画源码的实现
2021/03/09 HTML / CSS
Chrome Form多次提交表单问题的解决方法
2011/05/09 Javascript
表单类各种类型(文本框)失去焦点效果jquery代码
2013/04/26 Javascript
JS实现程序暂停与继续功能代码解读
2013/10/10 Javascript
Nodejs学习笔记之NET模块
2015/01/13 NodeJs
深入理解JavaScript中的对象
2015/06/04 Javascript
jQuery插件Easyui设置datagrid的pageNumber导致两次请求问题的解决方法
2016/08/06 Javascript
AngularJS  $on、$emit和$broadcast的使用
2016/09/05 Javascript
Vue自定义事件(详解)
2017/08/19 Javascript
浅谈node模块与npm包管理工具
2018/01/03 Javascript
浅谈Webpack下多环境配置的思路
2018/06/27 Javascript
浅析微信小程序自定义日历组件及flex布局最后一行对齐问题
2020/10/29 Javascript
[01:33]DOTA2上海特级锦标赛 LIQUID战队完整宣传片
2016/03/16 DOTA
[52:41]OG vs IG 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/20 DOTA
Ubuntu 14.04+Django 1.7.1+Nginx+uwsgi部署教程
2014/11/18 Python
Python爬虫教程之利用正则表达式匹配网页内容
2020/12/08 Python
HTML里显示pdf、word、xls、ppt的方法示例
2020/04/14 HTML / CSS
Speedo美国:澳大利亚顶尖泳衣制造商
2016/08/03 全球购物
泰国王权免税店官方网站:KingPower
2019/03/11 全球购物
Bath & Body Works阿联酋:在线购买沐浴和身体用品
2021/02/27 全球购物
写给女朋友的道歉信
2014/01/08 职场文书
学生会干部自荐信
2014/02/04 职场文书
护士毕业实习感言
2014/03/05 职场文书
中学生寄语大全
2014/04/03 职场文书
派出所班子党的群众路线对照检查材料思想汇报
2014/10/01 职场文书
深入理解以DEBUG方式线程的底层运行原理
2021/06/21 Java/Android
Nginx反向代理配置的全过程记录
2021/06/22 Servers
Golang的继承模拟实例
2021/06/30 Golang
各国货币符号大全
2022/02/17 杂记