php中文网最新课程
每日17点准时技术干货分享
PHP中插件机制的一种实现方法
插件,也即Plug-in,指的是一类特定的功能模块(一般由第三方研发者实现),它的特点是:当你需要它的时候激活它,不需要它的时候禁用/删除它;
且无 论是激活还是禁用都不影响系统核心模块的运行,亦便是说插件是一种非侵入式的模块化设计,实现了核心程序与插件程序的松散耦合。
一个典型的例子便是 Wordpress中众多的第三方插件,例如Akimet插件用于对用户的评论进行Spam过滤。
一个健壮的插件机制,我认为必须具备以下特点:
● 插件的动态监听和加载(Lookup)
● 插件的动态触发
以上两点的实现均不影响核心程序的运行
要在程序中实现插件,咱们首要应该想到的便是定义区别的钩子(Hooks);“钩子”是一个很形象的规律概念,你能够认为它是系统预留的插件触发要求。
它 的规律原理如下:当系统执行到某个钩子时,会判断这个钩子的要求是不是满足;倘若满足,会转而先去调用钩子所制定的功能,而后返回继续执行余下的程序;
倘若 不满足,跳过就可。这有点像汇编中的“中断守护”规律。
某些钩子可能是系统事先就设计好的,例如之前我举的关于评论Spam过滤的钩子,一般它已然由核心系统研发人员设计进了评论的处理规律中;
另一一类钩子则 可能是由于用户自动定制的(由第三方研发人员制定),一般存在于表现层,例如一个普通的PHP表单表示页面中。
可能你感觉上面的话比较无聊,让人昏昏欲睡;然则要看懂下面我写的代码,理解以上的原理是必不可少的。
下面进行PHP中插件机制的核心实现,全部机制核心分为三大块:
一个插件经理类:这是核心之核心。它是一个应用程序全局Global对象。它重点有三个职责:
● 负责监听已然注册了的所有插件,并实例化这些插件对象。
● 负责注册所有插件。
● 当钩子要求满足时,触发对应的对象办法。
插件的功能实现:这大多由第三方研发人员完成,但需要遵循必定的规则,这个规则是插件机制所规定的,因插件机制的区别而区别,下面的表示代码你会看到这个规则。
插件的触发:亦便是钩子的触发要求。
详细来讲这是一小段代码,安置在你需要插件实现的地区,用于触发这个钩子。
原理讲了一大堆,下面瞧瞧我的实现方法:
插件经理PluginManager类: <?/*** STBLOG PluginManager Class** 插件机制的实现核心类** @package STBLOG* @subpackage Libraries* @category Libraries* @author Saturn*/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; }}?>
以上代码加上注释不超过100行,就完成为了全部插件机制的核心。需要再次说明的是,你必须将它设置成全局类,在所有 需要用到插件的地区,优先加载。
用#注释的地区是你需要自动完成的部分,包含插件的获取和日志记录等等。
下面是一个简单插件的实现。 <?/*** 这是一个Hello World简单插件的实现** @package DEMO* @subpackage DEMO* @category Plugins* @author Saturn*//***需要重视的几个默认规则:* 1. 本插件类的文件名必须是action* 2. 插件类的名叫作必须是{插件名_actions}*/class DEMO_actions{ //解析函数的参数是pluginManager的引用 function __construct(&$pluginManager){//注册这个插件 //第1个参数是钩子的名叫作 //第二个参数是pluginManager的引用 //第三个是插件所执行的办法 $pluginManager->register(demo, $this, say_hello); } function say_hello(){ echo Hello World; }}?>
这是一个简单的Hello World插件,用于输出一句话。
在实质状况中,say_hello可能包含对数据库的操作,或是其他有些特定的规律,例如调用Akimet API。
插件实现的默认规则由核心系统研发者自动确定。
例如本例的有些默认规则我在注释中已然写的很清楚,这里不在赘述。需要尤其重视的是钩子名叫作不要重复。
最后一步,便是定义钩子的触发,你将钩子放在哪里,上面这个插件的办法就会在哪里出发。
例如我要将say_hello放到我博客首页Index.php, 那样你在index.php中的某个位置写下:
$pluginManager->trigger(demo,);
第1个参数暗示钩子的名字,在本例中它是demo;
第二个参数是插件对应办法的入口参数,因为这个例子中无输入参数,因此为空。
总结
本篇文案介绍了插件机制在PHP中实现的一种办法和思路,以及我自己对插件机制的理解。初次接触这个东西,可能会比较生涩,难以理解。然则当你结合真实的例子,再想想程序的运行流程,思路可能会更清晰有些。
▼请点击下方:“阅读原文”,在线查看所有文案内容!
|