php插件机制
首页本文主要记录自己学习的一个过程.
自己先编了一个插件的代码(当然这是一个错误的例子,只是为了验证自己的想法和真正的实现有什么区别和差距):
目录结构:
index.php //主文件
config.php //配置信息
plugin.php //插件类
plugin/echohello/echohello.php //插件1 echohello插件
plugin/echoworld/echoworld.php //插件2 echoworld插件
代码: plugin.php <?php class plugin{ //插件文件夹路径 public $ppath;
public function __construct($path) { $this->ppath = $path; } //装载插件 //params: // $pname:插件名称 public function plugin_add($pname) { $pluginpath = $this->ppath."/".$pname."/".$pname.".php"; //该插件路径为../plugin/$name文件夹 // echo $pluginpath; if(file_exists($pluginpath)) { include($pluginpath); } } //执行插件 //params : // $pname:插件名称 // $pmethod:插件方法 public function plugin_run($pname) { call_user_func($pname,"");//执行插件里面的方法 } }
config.php define(PLUGIN_PATH,__dir__."/plugin");//配置插件文件夹位置 index.php <?php require("plugin.php"); //包含插件类 require("config.php"); //包含配置文件 //-------plugin_start---------- $plugin = new plugin(PLUGIN_PATH); //实例化一个插件类 $plugin->plugin_add("echohello"); //调用插件类的方法装载一个名为echohello的插件 $plugin->plugin_run("echohello"); //运行这个echohello插件
$plugin->plugin_add("echoworld"); //同上 $plugin->plugin_run("echoworld"); //同上 //-------plugin_end----------
plugin/echohello/echohello.php //echohello插件 function echohello(){ echo "hello"; }
代码如上所示 这个我自己的想法,其实就是: 插件就是一个执行某个功能的function,然后通过一个类来包含进来这个function的路径,以及通过使用call_user_func()方法来调用这个function,然后在你需要的地方实例化一个插件类,调用插件类的装载和运行方法.来从而来实现插件中的function返回数据. 尼玛,这不就是一个变相的自动加载类吗.不过加载的不是类而是一个定义了方法的文件. 我的程序的几个问题 1.动态加载有了,动态监听在哪? 2.当删除了一个插件目录的时候会出错,因为你的插件信息中关于目录的访问太过于死板.规定了和插件名称一致的目录名称,而当插件名称改变,或者目录名称改变的时候就会出错. 3.程序太过冗余,不够灵活 后来看到另外一篇文章: http://developer.51cto.com/art/200912/168701.htm 上面说插件的几个特点: 1.插件的动态监听和加载 2.插件的动态触发
看了这篇文章,我重新写了一个例子 目录结构基本不变 plugin.php
<?php //全局插件类 //类似上面链接中的插件经理pluginmanager类
class plugin{
//监听数组,用来判断哪些插件被实例化了. //实例化的插件名称会自动加载到这个数组中去 private $_listener = array();
public function __construct() { //这边可以从数据库中读取信息 //例如可以有一张plugin表,里面记录了插件名称,插件路径,和状态是否开启/关闭 //读取状态开启的2个插件 1 echohello 2 echoworld $hasactiveplugins = array( "echohello" => array( "name" => "echohello", //我这边的规则是echohello插件目录下的echohello.php文件,你可以自己定义这个规则 "path" => "/echohello/", ), "echoworld" => array( "name" => "echoworld", "path" => "/echoworld/", ) );
//获取了hasactiveplugins数组,表示了这2个插件都是开启的,需要实例化他们 if($hasactiveplugins) { foreach($hasactiveplugins as $k => $v) { //插件的运行文件路径 $pluginfile = PLUGIN_PATH.$v["path"].$v["name"].".php"; if(file_exists($pluginfile)) { include_once($pluginfile); $classname = $v["name"]; //插件中的类明就是插件名称,规则自己定义 if(class_exists($classname)) { //这边为什么要在实例化插件功能类的时候给他参数是插件管理类呢? //这是因为在插件功能类中,构造函数中需要调用插件管理类的注册方法,将该插件注册到监听数组中去 new $classname($this); }
} } } }
//插件的注册方法,主要负责将实例化的插件注册到监听列表中,表示这个插件是可用的 //这边的注册还可以包含插件方法,也就是这个插件的哪些方法被注册了可以使用. public function register($hook,&$pluginobject,$method) { $key = get_class(&$pluginobject)."-".$method;//这边跟上面例子不同,我用了- 而不是-> 我怕这个符号会让我自己都不明白 //其实这个$key只是为了在监听数组中记录一下而已,命名一下. $this->_listener[$hook][$key] = array(&$pluginobject,$method); }
public function run($hook) //也就是例子中的trigger名为触发,我这边定义誠run,执行的意思,个人爱好 { $result = ""; //执行监听中的方法 //首先判断监听数组中是否有记录. if(isset($this->_listener[$hook]) && is_array($this->_listener[$hook]) && count($this->_listener[$hook]) > 0) { // print_r($this->_listener); //如果有数据,那么执行方法返回数据 foreach($this->_listener[$hook] as $k => $v) { $classname = $v[0]; $classmethod = $v[1];
//这边就知道了为什么register的参数中$pluginobject 对象参数用的是&$pluginobject,地址传递.因为首先判断有没有这个方法 //需要使用到method_exists()而这个方法需要给予object对象类型 //注意你给的参数不能命名为&$this,我就刚刚犯了这个错误 //当然你也可以不给予地址传递,直接传类名,然后在这里实例化一个对象来调用method方法.不过那样比较废 if(method_exists($classname,$classmethod)) { $result .= $classname->$classmethod(); } } } return $result; } }
index.php <?php require("config.php"); require("plugin.php");//全局插件类 //主运行文件
//在想要显示插件数据的地方加载代码 $newplugin = new plugin();
$newplugin->run("echohello");
$newplugin->run("echoworld");
plugin/echohello/echohello.php <?php //插件echohello class echohello { public function __construct($plugin) { $plugin->register("echohello",$this,"printstr"); }
//printstr方法 public function printstr() { echo "hello!"; }
} 监听数组的意思,我个人理解,其实就是一个那些插件被激活开启的数组. 你所需要做的就是从数据库中查询哪些插件是被激活的,并且将他们的信息存入监听数组中去,然后实现监听数组中的方法. 上面的例子中,监听数组是一个二维数组,$this->$_listener[$hook] ,$hook代表的是钩子,其实也就是是一个地方的标识符.在具有该标识符的位置放入该标识符中所有的插件名称中定义的插件方法. 那监听的意思也就是相当于已激活插件列表
代码: plugin.php <?php class plugin{ //插件文件夹路径 public $ppath;
public function __construct($path) { $this->ppath = $path; } //装载插件 //params: // $pname:插件名称 public function plugin_add($pname) { $pluginpath = $this->ppath."/".$pname."/".$pname.".php"; //该插件路径为../plugin/$name文件夹 // echo $pluginpath; if(file_exists($pluginpath)) { include($pluginpath); } } //执行插件 //params : // $pname:插件名称 // $pmethod:插件方法 public function plugin_run($pname) { call_user_func($pname,"");//执行插件里面的方法 } }
config.php define(PLUGIN_PATH,__dir__."/plugin");//配置插件文件夹位置 index.php <?php require("plugin.php"); //包含插件类 require("config.php"); //包含配置文件 //-------plugin_start---------- $plugin = new plugin(PLUGIN_PATH); //实例化一个插件类 $plugin->plugin_add("echohello"); //调用插件类的方法装载一个名为echohello的插件 $plugin->plugin_run("echohello"); //运行这个echohello插件
$plugin->plugin_add("echoworld"); //同上 $plugin->plugin_run("echoworld"); //同上 //-------plugin_end----------
plugin/echohello/echohello.php //echohello插件 function echohello(){ echo "hello"; }
代码如上所示 这个我自己的想法,其实就是: 插件就是一个执行某个功能的function,然后通过一个类来包含进来这个function的路径,以及通过使用call_user_func()方法来调用这个function,然后在你需要的地方实例化一个插件类,调用插件类的装载和运行方法.来从而来实现插件中的function返回数据. 尼玛,这不就是一个变相的自动加载类吗.不过加载的不是类而是一个定义了方法的文件. 我的程序的几个问题 1.动态加载有了,动态监听在哪? 2.当删除了一个插件目录的时候会出错,因为你的插件信息中关于目录的访问太过于死板.规定了和插件名称一致的目录名称,而当插件名称改变,或者目录名称改变的时候就会出错. 3.程序太过冗余,不够灵活 后来看到另外一篇文章: http://developer.51cto.com/art/200912/168701.htm 上面说插件的几个特点: 1.插件的动态监听和加载 2.插件的动态触发
看了这篇文章,我重新写了一个例子 目录结构基本不变 plugin.php
<?php //全局插件类 //类似上面链接中的插件经理pluginmanager类
class plugin{
//监听数组,用来判断哪些插件被实例化了. //实例化的插件名称会自动加载到这个数组中去 private $_listener = array();
public function __construct() { //这边可以从数据库中读取信息 //例如可以有一张plugin表,里面记录了插件名称,插件路径,和状态是否开启/关闭 //读取状态开启的2个插件 1 echohello 2 echoworld $hasactiveplugins = array( "echohello" => array( "name" => "echohello", //我这边的规则是echohello插件目录下的echohello.php文件,你可以自己定义这个规则 "path" => "/echohello/", ), "echoworld" => array( "name" => "echoworld", "path" => "/echoworld/", ) );
//获取了hasactiveplugins数组,表示了这2个插件都是开启的,需要实例化他们 if($hasactiveplugins) { foreach($hasactiveplugins as $k => $v) { //插件的运行文件路径 $pluginfile = PLUGIN_PATH.$v["path"].$v["name"].".php"; if(file_exists($pluginfile)) { include_once($pluginfile); $classname = $v["name"]; //插件中的类明就是插件名称,规则自己定义 if(class_exists($classname)) { //这边为什么要在实例化插件功能类的时候给他参数是插件管理类呢? //这是因为在插件功能类中,构造函数中需要调用插件管理类的注册方法,将该插件注册到监听数组中去 new $classname($this); }
} } } }
//插件的注册方法,主要负责将实例化的插件注册到监听列表中,表示这个插件是可用的 //这边的注册还可以包含插件方法,也就是这个插件的哪些方法被注册了可以使用. public function register($hook,&$pluginobject,$method) { $key = get_class(&$pluginobject)."-".$method;//这边跟上面例子不同,我用了- 而不是-> 我怕这个符号会让我自己都不明白 //其实这个$key只是为了在监听数组中记录一下而已,命名一下. $this->_listener[$hook][$key] = array(&$pluginobject,$method); }
public function run($hook) //也就是例子中的trigger名为触发,我这边定义誠run,执行的意思,个人爱好 { $result = ""; //执行监听中的方法 //首先判断监听数组中是否有记录. if(isset($this->_listener[$hook]) && is_array($this->_listener[$hook]) && count($this->_listener[$hook]) > 0) { // print_r($this->_listener); //如果有数据,那么执行方法返回数据 foreach($this->_listener[$hook] as $k => $v) { $classname = $v[0]; $classmethod = $v[1];
//这边就知道了为什么register的参数中$pluginobject 对象参数用的是&$pluginobject,地址传递.因为首先判断有没有这个方法 //需要使用到method_exists()而这个方法需要给予object对象类型 //注意你给的参数不能命名为&$this,我就刚刚犯了这个错误 //当然你也可以不给予地址传递,直接传类名,然后在这里实例化一个对象来调用method方法.不过那样比较废 if(method_exists($classname,$classmethod)) { $result .= $classname->$classmethod(); } } } return $result; } }
index.php <?php require("config.php"); require("plugin.php");//全局插件类 //主运行文件
//在想要显示插件数据的地方加载代码 $newplugin = new plugin();
$newplugin->run("echohello");
$newplugin->run("echoworld");
plugin/echohello/echohello.php <?php //插件echohello class echohello { public function __construct($plugin) { $plugin->register("echohello",$this,"printstr"); }
//printstr方法 public function printstr() { echo "hello!"; }
} 监听数组的意思,我个人理解,其实就是一个那些插件被激活开启的数组. 你所需要做的就是从数据库中查询哪些插件是被激活的,并且将他们的信息存入监听数组中去,然后实现监听数组中的方法. 上面的例子中,监听数组是一个二维数组,$this->$_listener[$hook] ,$hook代表的是钩子,其实也就是是一个地方的标识符.在具有该标识符的位置放入该标识符中所有的插件名称中定义的插件方法. 那监听的意思也就是相当于已激活插件列表
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。