反射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);
更多在PHP中使用反射技術的架構插件使用說明相關文章請關注PHP中文網!