超碰97资源在线免费观看-国产亚洲一区二区久久-欧美日韩成人字幕一区-激情五月网在线视频-亚洲天堂美女av在线-麻豆视传媒精品av-婷婷激情综合激情五月俺也去-国产精品久久久久久亚洲av站-51精产国品一二三产区区,久久久久久久区二区三区四区久久久,色哟哟视频国产精品,日韩va亚洲va欧美

中山php|最優(yōu)網(wǎng)絡(luò)中山做網(wǎng)站 中山php建站

最優(yōu)良人

2011/08/26 at 00:06

什么是php反射機(jī)制以及利用php反射機(jī)制實(shí)現(xiàn)可插拔可擴(kuò)展的插件架構(gòu)

反射是什么?
它是指在PHP運(yùn)行狀態(tài)中,擴(kuò)展分析PHP程序,導(dǎo)出或提取出關(guān)于類(lèi)、方法、屬性、參數(shù)等的詳細(xì)信息,包括注釋。這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱(chēng)為反射API。

反射是操縱面向?qū)ο蠓缎椭性P偷腁PI,其功能十分強(qiáng)大,可幫助我們構(gòu)建復(fù)雜,可擴(kuò)展的應(yīng)用。其用途如:自動(dòng)加載插件,自動(dòng)生成文檔,甚至可用來(lái)擴(kuò)充PHP語(yǔ)言。php反射api由若干類(lèi)組成,可幫助我們用來(lái)訪(fǎng)問(wèn)程序的元數(shù)據(jù)或者同相關(guān)的注釋交互。借助反射我們可以獲取諸如類(lèi)實(shí)現(xiàn)了那些方法,創(chuàng)建一個(gè)類(lèi)的實(shí)例(不同于用new創(chuàng)建),調(diào)用一個(gè)方法(也不同于常規(guī)調(diào)用),傳遞參數(shù),動(dòng)態(tài)調(diào)用類(lèi)的靜態(tài)方法。
*
**
反射api是php內(nèi)建的oop技術(shù)擴(kuò)展,包括一些類(lèi),異常和接口,綜合使用他們可用來(lái)幫助我們分析其它類(lèi),接口,方法,屬性,方法和擴(kuò)展。這些oop擴(kuò)展被稱(chēng)為反射,位于php源碼/ext/reflection目錄下。

可以使用反射api自省反射api本身(這可能就是反射最初的意思,自己"看"自己):
<?php
Reflection::export(new ReflectionExtension('reflection'));
?>
幾乎所有的反射api都實(shí)現(xiàn)了reflector接口,所有實(shí)現(xiàn)該接口的類(lèi)都有一個(gè)export方法,該方法打印出參數(shù)對(duì)象的相關(guān)信息。
使用get_declared_classes()獲取所有php內(nèi)置類(lèi),get_declared_interfaces();
get_defined_functions();
get_defined_vars(); get_defined_constants();可獲取php接口,方法,變量,常量信息。

**
***
反射初探:
<?php
//定義一個(gè)自定義類(lèi)
class MyTestClass{

public function testFunc($para0='defaultValue0'){

}
}
//接下來(lái)反射它
foreach(get_declared_classes() as $class){
//實(shí)例化一個(gè)反射類(lèi)
$reflectionClass = new ReflectionClass($class);
//如果該類(lèi)是自定義類(lèi)
if($reflectionClass->isUserDefined()){
//導(dǎo)出該類(lèi)信息
Reflection::export($reflectionClass);
}
}
?>
以上片段實(shí)例如何查看自定義類(lèi)的基本信息。
描述數(shù)據(jù)的數(shù)據(jù)被稱(chēng)為元數(shù)據(jù),用反射獲取的信息就是元數(shù)據(jù)信息,這些信息用來(lái)描述類(lèi),接口方法等等。(元---》就是原始之意,比如元模型就是描述模型的模型,比如UML元模型就是描述UML結(jié)構(gòu)的模型),元數(shù)據(jù)進(jìn)一步可分為硬元數(shù)據(jù)(hard matadata)和軟元數(shù)據(jù)(soft metadata),前者由編譯代碼導(dǎo)出,如類(lèi)名字,方法,參數(shù)等。
后者是人為加入的數(shù)據(jù),如phpDoc塊,php中的屬性等。
***
****
現(xiàn)在商業(yè)軟件很多都是基于插件架構(gòu)的,比如eclipse,和visual studio,netbeans等一些著名IDE都是基于插件的GUI應(yīng)用。第三方或本方開(kāi)發(fā)插件時(shí),必須導(dǎo)入定義好的相關(guān)接口,然后實(shí)現(xiàn)這些接口,最后把實(shí)現(xiàn)的包放在指定目錄下,宿主應(yīng)用程序在啟動(dòng)時(shí)自動(dòng)檢測(cè)所有的插件實(shí)現(xiàn),并加載它們。如果我們自己想實(shí)現(xiàn)這樣的架構(gòu)也是可能的。
<?php
//先定義UI接口
interface IPlugin {
//獲取插件的名字
public static function getName();
//要顯示的菜單項(xiàng)
function getMenuItems();
//要顯示的文章
function getArticles();
//要顯示的導(dǎo)航欄
function getSideBars();
}
//一下是對(duì)插件接口的實(shí)現(xiàn)
class SomePlugin implements IPlugin {
public function getMenuItems() {
//返回菜單項(xiàng)
return null;
}
public function getArticles() {
//返回我們的文章
return null;
}
public function getSideBars() {
//我們有一個(gè)導(dǎo)航欄
return array('SideBarItem');
}
//返回插件名
public static function getName(){
return "SomePlugin";
}
}
?>
php中也有使用插件的解決方案,不像eclipse。

使用我們的插件:1.先使用get_declared_classes()獲取所有已加載類(lèi)。2.遍歷所有類(lèi),判斷其是否實(shí)現(xiàn)了我們自定義的插件接口IPlugin。3.獲取所有的插件實(shí)現(xiàn)。4.在宿主應(yīng)用中與插件交互
下面這個(gè)方法幫助我們找到實(shí)現(xiàn)了插件接口的所有類(lèi):
function findPlugins() {
$plugins = array();
foreach(get_declared_classes() as $class) {
$reflectionClass = new ReflectionClass($class);
//判斷一個(gè)類(lèi)是否實(shí)現(xiàn)了IPlugin接口
if($reflectionClass->implementsInterface('IPlugin')) {
$plugins[] = $reflectionClass;
}
}
return $plugins;
}
注意到所有的插件實(shí)現(xiàn)是作為反射類(lèi)實(shí)例返回的,而不是類(lèi)名本身,或是類(lèi)的實(shí)例。因?yàn)槿绻褂梅瓷鋪?lái)調(diào)用方法還需要一些條件判斷。

判斷一個(gè)類(lèi)是否實(shí)現(xiàn)了某個(gè)方法使用反射類(lèi)的hasMethod()方法。
接下來(lái)我們把所有的插件菜單項(xiàng)放在一個(gè)菜單上。
function integratePlugInMenus() {
$menu = array();
//遍歷所有的插件實(shí)現(xiàn)
foreach(findPlugins() as $plugin) {
//判斷插件是否實(shí)現(xiàn)了getMenuItems方法
if($plugin->hasMethod('getMenuItems')) {
/*實(shí)例化一個(gè)方法實(shí)例(注意當(dāng)你將類(lèi)和方法看成概念時(shí),它們就可以有實(shí)例,就像"人"這個(gè)概念一樣),該方法返回的是ReflectionMethod的實(shí)例*/
$reflectionMethod = $plugin->getMethod('getMenuItems');
//如果方法是靜態(tài)的
if($reflectionMethod->isStatic()) {
//調(diào)用靜態(tài)方法,注意參數(shù)是null而不是一個(gè)反射類(lèi)實(shí)例
$items = $reflectionMethod->invoke(null);
} else {
//如果方法不是靜態(tài)的,則先實(shí)例化一個(gè)反射類(lèi)實(shí)例所代表的類(lèi)的實(shí)例。
$pluginInstance = $plugin->newInstance();
//使用反射api來(lái)調(diào)用一個(gè)方法,參數(shù)是通過(guò)反射實(shí)例化的對(duì)象引用
$items = $reflectionMethod->invoke($pluginInstance);
}
//合并所有的插件菜單項(xiàng)為一個(gè)菜單。
$menu = array_merge($menu, $items);
}
}
return $menu;
}
這里主要用到的反射方法實(shí)例的方法調(diào)用:
public mixed invoke(stdclass object, mixed args=null);
請(qǐng)一定搞清楚我們常規(guī)方法的調(diào)用是這種形式:$objRef->someMethod($argList...);
因?yàn)槭褂昧朔瓷洌@時(shí)你在想調(diào)用一個(gè)方法時(shí)形式變?yōu)椋?br /> $reflectionMethodRef->invoke($reflectionClassRef,$argList...);
如果使用反射調(diào)用方法,我們必須實(shí)例化一個(gè)反射方法的實(shí)例,如果是實(shí)例方法還要有一個(gè)實(shí)例的引用,可能還需傳遞必要的參數(shù)。當(dāng)調(diào)用一個(gè)靜態(tài)方法時(shí),顯式傳入null作為第一參數(shù)。
對(duì)插件類(lèi)實(shí)現(xiàn)的其他方法有類(lèi)似的處理邏輯,這里不再敷述。
以下是我的一個(gè)簡(jiǎn)單測(cè)試:
<?php
/**
* 定義一個(gè)插件接口
* */
interface IPlugIn
{
/**
* getSidebars()
*
* @return 返回側(cè)導(dǎo)航欄
*/
public function getSidebars();
/**
* GetName()
*
* @return 返回類(lèi)名
*/
public static function GetName();
}

/*下面是對(duì)插件的實(shí)現(xiàn),其實(shí)應(yīng)該放在不同的文件中,甚至是不同的包中*/
class MyPlugIn implements IPlugIn
{
public function getSidebars()
{
//構(gòu)造自己的導(dǎo)航欄
$sideBars = '<div><ul >
<li><a href="">m1</a>
</li>
<li><a href="">m2</a>
</li>
</ul>
</div>';
return $sideBars;
}
public static function GetName()
{
return 'MyPlugIn';
}
}
//第二個(gè)插件實(shí)現(xiàn);
class MyPlugIn2 implements IPlugIn
{
public function getSidebars()
{
//構(gòu)造自己的導(dǎo)航欄
$sideBars = '<div><ul >
<li><a href="">mm1</a>
</li>
<li><a href="">mm2</a>
</li>
</ul>
</div>';
return $sideBars;
}
public static function GetName()
{
return 'MyPlugIn2';
}
}

//在宿主程序中使用插件
class HostApp
{

public function initAll()
{
// 初始化各個(gè)部分
echo "yiqing95.";
$this->renderAll();
}
//渲染GUI格部分
function renderAll(){
$rsltSidebars="<table>";
foreach($this->integrateSidebarsOfPlugin() as $sidebarItem){
$rsltSidebars.="<tr><td>$sidebarItem</td></tr>";
}
$rsltSidebars.="</table>";

echo $rsltSidebars;
}
/*加載所有的插件實(shí)現(xiàn):*/
protected function findPlugins()
{
$plugins = array();
foreach (get_declared_classes() as $class) {
$reflectionClass = new ReflectionClass($class);
if ($reflectionClass->implementsInterface('IPlugin')) {
$plugins[] = $reflectionClass;
}
}
return $plugins;
}
/**加載組裝所有插件實(shí)現(xiàn)***/
protected function integrateSidebarsOfPlugin()
{
$sidebars = array();
foreach ($this->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);
$sidebars[]=$items;
}
return $sidebars;
}

}
//運(yùn)行程序:
$entryClass =new HostApp();
$entryClass->initAll();
?>
****
××××
$reflectionClass = new ReflectionClass("IPlugIn");
echo $reflectionClass-> getDocComment();
這段代碼可以幫助我們獲取類(lèi)的文檔注釋?zhuān)坏┪覀儷@取了類(lèi)的注釋內(nèi)容我們就可以擴(kuò)展我們的類(lèi)功能,比如先獲取注釋?zhuān)缓蠓治鲎⑨屖褂胐ocblock tokenizer 『pecl擴(kuò)展』,或使用自帶的Tokenizer類(lèi)又或者使用正則表達(dá)式,字符串函數(shù)來(lái)解析注釋文檔,你可以在注釋中加入任何東西,包括指令,在使用反射調(diào)用前可判斷這些通過(guò)注釋傳遞的指令或數(shù)據(jù):
<?php
//"分析相關(guān)的注釋數(shù)據(jù)"
analyse($reflectionClass-> getDocComment());//analyse是自己定義的?。?!
//根據(jù)分析的結(jié)果來(lái)執(zhí)行方法,或者傳遞參數(shù)等
if(xxxx){
$reflectionMethod->invoke($pluginInstance) ;
}
?>
因?yàn)樽⑨尞吘故亲址梢允褂萌魏巫址馕黾夹g(shù),提取有用的信息,再根據(jù)這些信息來(lái)調(diào)用方法,就是說(shuō)程序的邏輯不光可由方法實(shí)現(xiàn)決定,還可能由注釋決定(前提是你使用了反射,注釋格式嚴(yán)格有要求)。
××××
*****
反射api和其他類(lèi)一樣可被繼承擴(kuò)展,所以我們可以為這些api添加自己的功能。結(jié)合自定義注釋標(biāo)記。就是以@開(kāi)頭的東東,標(biāo)注(Java中稱(chēng)為annotation),.net中稱(chēng)為屬性attribute(或稱(chēng)為特性)。然后擴(kuò)展Reflection類(lèi),就可以實(shí)現(xiàn)強(qiáng)大的擴(kuò)展功能了。
值得一提的是工廠(chǎng)方法設(shè)計(jì)模式(GOF之一),也常使用反射來(lái)實(shí)例化對(duì)象,下面是示例性質(zhì)的偽碼:
Class XXXFactory{
function getInstance($className){
$reflectionClass =new ReflectionClass($className);
return $reflectionClass->newInstance();
}
//使用接口的那個(gè)類(lèi)實(shí)現(xiàn),可能來(lái)自配置文件
function getInstance(){
$pathOfConfig = "xxx/xx/XXXImplement.php";
$className= Config->getItem($pathOfClass,'SomeClassName');
return $this->getInstance($className);
}
}
*****

標(biāo)簽:,
-
色婷婷婷婷婷婷婷婷婷婷-黑人玩弄人妻一区二区绿帽子-日韩人妻不卡一区二区三区-精品久久久久久久久久18禁电影 | 粉嫩性色av一区二区三区蜜臀-男人的天堂亚洲最新在线-日韩黄色一级网站视频-精品91久久久久a | 精品视频蜜桃久久久久-日韩美免费观看视频-精品99国产乱码久久久久密-久久久久久亚洲女同第一区暖暖 | 91成人区人妻精品一区二区不卡-久久精品久久久久久久婷婷-yeezy350亚洲限定色-91夜夜蜜桃一区二区三区 | 91精品久久久久久久久久入口-精品中文字幕一区二区三区av-欧美国产在线视频一区二区-欧美熟妇激情一区二区三区 | 精品人妻一区二区三区人妻-久久午夜夜伦鲁鲁片不卡-日韩性生活一级视频-国产又粗又猛又爽又黄的视 | 国产成人av综合亚洲free-日韩人妻中文字幕av-高清日韩一区二区三区视频-夜夜嗨av一区二区三区网站 | 91一区二区三区四区五区-久久av一级av少妇av高潮-人妻精品久久久久中文字幕69美1-免费av一区二区三区四区 | 日韩a不卡av在线-久久 99 热 这里有精品-日韩亚洲中文字幕av有码-精品久久伦理片 | 91在线综合网亚洲-天天操夜夜操夜夜爽爽-中文字幕一区二区三区最新-人妻乱码一区二区 | 天天干天天躁久久综合-1024人妻一区二区三区-蜜桃久久久亚洲精品成-国产欧美日韩各 | 1024你懂的在线观看视频-中日韩一区二区三区视频-久久中文字幕资源网-懂色av中文一区二区三区四区 | 国产乱码一区二区三区爽爽爽免费-18禁国精品久久久久久-日韩人妻中文字幕首页-久久久国产精品久久久久久 | 久久久精品国产臀蜜-色婷婷综合久久久久中文国产精品-日韩熟女av天堂-97香蕉久久国产超碰青草最新版 | yellow中文字幕91最-亚洲精品国产精品国自产2020-丰满人妻一区二区视频-人妻系列中文字幕版 | 97一区二区三区人妻免费-欧美日韩成人在线视频网站-精品人妻人伦一二三久久久久-日韩激情四季av粉嫩av | 国产av一区二本三区-日韩欧美精品熟女-超碰97在线免费人妻-国产夫妻啪啪啪啪啪 | 久久久久久人妻一区精品69-婷婷 在线 亚洲-蜜桃久久久亚洲精品在线在线-中文字幕成人乱码视频 | 精品国产91蜜臀内射久久-国产成人小视频在线-99久在线国内在线播放免费观看-蜜桃臀久久久久婷婷免费视频 | 成人熟女俱乐部-色婷婷精品一区=区-亚洲天堂中文字幕一区二区三区免费-日韩三级电影一区 | 国产欧美一区二区三区四区视频-国产成人综合av一区二区三区-六月婷婷综合五月天-国产成人自拍视频在线观看 | 久久热这里只精品99-久久精品国产熟女精品-日本精品久久久久中文字幕-国产精品91在线播放 | 成人福利在线观看免费-久久久一区二区国产-中文字幕人妻熟女人妻av网站-成人精品91在线观看 | 丁香婷婷在线中文字幕-日日躁夜夜躁狠狠躁超碰-精品久久中文字幕巨乳-日韩免费av电影不卡 | 99超碰人妻精品一二三-亚洲一区二区三区一级在线-中文字幕熟女激情-欧美日韩一级作a一区二区 | 91麻豆精品亚洲永久-亚洲a资源在线观看-乱子伦一区二区三区视频在线观看麻-超碰97资源在线免费观看 | 精品国产精品色哟哟-岛国av中文字幕在线观看-久久久999精品国产-乱人视频中文字幕 | 欧美国精产品一二区-国产美女福利视频一区二区三区-99精品久久精品视频-日韩有码中文字幕一区 | 日韩精品人妻中文字幕有码欧美-日韩午夜一级福利-欧美日韩国产一区二区三区在线观看-超碰97人妻巨乳 | av精品一区二区三-中文字幕日韩人妻在线视频-国产超碰在线播放99-久久久久久国产精品,国产 | 亚洲欧美在线999-久久久精品久久99-久久精品人妻一区二区三区蜜桃-丁香花婷婷在线激情 | 中文字幕一区二区三区av-超碰在线免费免费观看97-91久久久久久久免费-久久中文字幕3区 | 久久中文字幕人妻熟女-年轻的妈妈2在线观看中文字幕-国产国产国产国产国产av-超碰在线人妻中文 | 91国精产品一区二区三区-2021中文在线热码视频-国产精品99久久久久久成人四虎-九九在线视频免费看 | 国产精品久久久久久亚洲精品-久久精品国产91麻豆精品-国内精品99久久免费看-丰满人妻少妇久久久久 | 1024你懂的在线观看视频-中日韩一区二区三区视频-久久中文字幕资源网-懂色av中文一区二区三区四区 | 天天插天天日天天射天天干天天插-国产精品久久久久大片-国产av一区二区三区在线-国产 青青青 视频 | 国产三级视频一区二区在线观看-成人av欧美在线网站-91久久精品人妻一区二区-国产伦精一品二品三品 | 免费中文字幕视频在线播放-麻豆国产一二三专区在线观看-久久精品国产亚洲麻豆-日韩av中文字幕人妻一二区 | 91精品国产综合久久久免费看-高清不卡免费av在线播放-日韩成人极品在线内射3p蜜臀-99re国内外精品视频 | 亚洲国产麻豆影视久久久精品免费av-伊人久久综合大香蕉-高清国产成人亚洲综合91精品-欧美老熟妇激情 |