在PHP中使用反射技术的架构插件使用说明
程序员文章站
2023-11-03 20:38:34
反射api的插件方法是基于在运行时决定程序的功能来实现的,也就是说,它允许创建可选的接口方法,并在首次使用时检测到这部分接口方法,只有在插件中存在这部分接口的情况下,它们才...
反射api的插件方法是基于在运行时决定程序的功能来实现的,也就是说,它允许创建可选的接口方法,并在首次使用时检测到这部分接口方法,只有在插件中存在这部分接口的情况下,它们才会被用到.
假设拥有这样的接口
interface iplugin{
function getmenuitems();
function getarticles();
function getsidebars();
}
class someplugin implelents iplugin{
public function getmenuitems(){
//没有菜单项
return null;
}
public function getarticles(){ //没有任何文章
return null;
}
public function getsidbars(){
//有侧边
return array("sidbaritem');
}
}
[html]
这种情况并不太合理,因为满足了接口的要求,为大量方法添加了不会用到的函数体,如果在api中有数百个方法,这样是行不通的。
反射api提供了一种解决方法,使用get_declared_classes()函数取得当前加载的类,并检测哪个类实现了iplugin"标记"的方法。
在这里写了一个使用反射查找插件的方法
[code]
function findplugins(){
$plugins=array();
foreach (get_declared_classes() as $class){
$reflectionsclass=new reflectionclass($class);
if($reflectionsclass->implementsinterface('iplugin')){
$plugins[]=$reflectionsclass;
}
}
return $plugins;
}
为了为了确定类是否实现了单个方法,可以使用refectionclass类的hasmethod()方法。
确定用于菜单的类的成员
function computermenu(){
$menu=array();
foreach (findplugins() as $plugin){
if($plugin->hasmethod('getmenuitems')){
$reflectionmethod=$plugin->getmethod('getmenuitems');
if($reflectionmethod->isstatic()){
$items=$reflectionmethod->invoke(null);
}else{
$plugininstance=$plugin->newinstance();
$items=$reflectionmethod->invoke($plugininstance);
}
$menu=array_merge($menu,$items);
}
}
return $menu;
}
得到类的实例后,需要检测是否能够静态检测调用api方法,如果方法是静态的,只需要调用 invoke()函数,
如下 public mixed invoke(stdclass object,mixed args=null)
另一方面,如果方法不是静态的,需要取得插件的一个实例来调用这个方法,要从refectionclass对象取得类的一个实例,
调用 它的newinstance()方法,然后再使用invoke()方法,返回实例传入就可以。
确定用于文章和侧边的类的成员
function computearticles(){
$articles=array();
foreach (findplugins() as $plugin){
if($plugin->hasmethod('getarticles')){
$reflectionmethod=$plugin->getmethod('getarticles');
if($reflectionmethod->isstatic()){
$items=$reflectionmethod->invoke(null);
}else{
$plugininstance=$plugin->newinstance();
$items=$reflectionmethod->invoke($plugininstance);
}
$articles=array_merge($articles,$items);
}
}
return $articles;
}
function computesidebars(){
$sidebars=array();
foreach (findplugins() as $plugin){
if($plugin->hasmethod('getsidebars')){
$reflectionmethod=$plugin->getmethod('getsidebars');
if($reflectionmethod->isstatic()){
$items=$reflectionmethod->invoke(null);
}else{
$plugininstance=$plugin->newinstance();
$items=$reflectionmethod->invoke($plugininstance);
}
$sidebars=array_merge($sidebars,$items);
}
}
return $sidebars;
}
创建一个实现了可选特性的反射式插件
class mycoolplugin implements iplugin{
public static function getname(){return 'mycoolplugin';}
public static function getmenuitems(){
//菜单项的数字索引数组
return array(array('description'=>'mycoolplugin','link'=>'/mycoolplugin'));
}
public static function getarticles(){
//文章的数字索引数组
return array(array('path'=>'/mycoolplugin','title'=>'this is a really cool article',
'text'=>'this article is cool because...'));
}
public static function getsidebars(){
//文章的侧边栏索引数组
return array(array('sidebars'=>'/mycoolplugin'));
}
}
最后只要这样就可以使用这样插件了:
$menu=computearticles();
$sidebars=computesidebars();
$articles=computearticles();
print_r($menu);
print_r($sidebars);
print_r($articles);
假设拥有这样的接口
复制代码 代码如下:
interface iplugin{
function getmenuitems();
function getarticles();
function getsidebars();
}
class someplugin implelents iplugin{
public function getmenuitems(){
//没有菜单项
return null;
}
public function getarticles(){ //没有任何文章
return null;
}
public function getsidbars(){
//有侧边
return array("sidbaritem');
}
}
[html]
这种情况并不太合理,因为满足了接口的要求,为大量方法添加了不会用到的函数体,如果在api中有数百个方法,这样是行不通的。
反射api提供了一种解决方法,使用get_declared_classes()函数取得当前加载的类,并检测哪个类实现了iplugin"标记"的方法。
在这里写了一个使用反射查找插件的方法
[code]
function findplugins(){
$plugins=array();
foreach (get_declared_classes() as $class){
$reflectionsclass=new reflectionclass($class);
if($reflectionsclass->implementsinterface('iplugin')){
$plugins[]=$reflectionsclass;
}
}
return $plugins;
}
为了为了确定类是否实现了单个方法,可以使用refectionclass类的hasmethod()方法。
确定用于菜单的类的成员
复制代码 代码如下:
function computermenu(){
$menu=array();
foreach (findplugins() as $plugin){
if($plugin->hasmethod('getmenuitems')){
$reflectionmethod=$plugin->getmethod('getmenuitems');
if($reflectionmethod->isstatic()){
$items=$reflectionmethod->invoke(null);
}else{
$plugininstance=$plugin->newinstance();
$items=$reflectionmethod->invoke($plugininstance);
}
$menu=array_merge($menu,$items);
}
}
return $menu;
}
得到类的实例后,需要检测是否能够静态检测调用api方法,如果方法是静态的,只需要调用 invoke()函数,
如下 public mixed invoke(stdclass object,mixed args=null)
另一方面,如果方法不是静态的,需要取得插件的一个实例来调用这个方法,要从refectionclass对象取得类的一个实例,
调用 它的newinstance()方法,然后再使用invoke()方法,返回实例传入就可以。
确定用于文章和侧边的类的成员
复制代码 代码如下:
function computearticles(){
$articles=array();
foreach (findplugins() as $plugin){
if($plugin->hasmethod('getarticles')){
$reflectionmethod=$plugin->getmethod('getarticles');
if($reflectionmethod->isstatic()){
$items=$reflectionmethod->invoke(null);
}else{
$plugininstance=$plugin->newinstance();
$items=$reflectionmethod->invoke($plugininstance);
}
$articles=array_merge($articles,$items);
}
}
return $articles;
}
function computesidebars(){
$sidebars=array();
foreach (findplugins() as $plugin){
if($plugin->hasmethod('getsidebars')){
$reflectionmethod=$plugin->getmethod('getsidebars');
if($reflectionmethod->isstatic()){
$items=$reflectionmethod->invoke(null);
}else{
$plugininstance=$plugin->newinstance();
$items=$reflectionmethod->invoke($plugininstance);
}
$sidebars=array_merge($sidebars,$items);
}
}
return $sidebars;
}
创建一个实现了可选特性的反射式插件
复制代码 代码如下:
class mycoolplugin implements iplugin{
public static function getname(){return 'mycoolplugin';}
public static function getmenuitems(){
//菜单项的数字索引数组
return array(array('description'=>'mycoolplugin','link'=>'/mycoolplugin'));
}
public static function getarticles(){
//文章的数字索引数组
return array(array('path'=>'/mycoolplugin','title'=>'this is a really cool article',
'text'=>'this article is cool because...'));
}
public static function getsidebars(){
//文章的侧边栏索引数组
return array(array('sidebars'=>'/mycoolplugin'));
}
}
最后只要这样就可以使用这样插件了:
复制代码 代码如下:
$menu=computearticles();
$sidebars=computesidebars();
$articles=computearticles();
print_r($menu);
print_r($sidebars);
print_r($articles);
上一篇: Python+OpenCV图片局部区域像素值处理改进版详解
下一篇: 更省力了呢