在PHP中使用反射技术的架构插件使用说明

  反射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);