免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
PHP反射介紹及利用反射實現(xiàn)插件功能
反射是操縱面向?qū)ο蠓缎椭性P偷腁PI,其功能十分強(qiáng)大,可幫助我們構(gòu)建復(fù)雜,可擴(kuò)展的應(yīng)用。其用途如:自動加載插件,自動生成文檔,甚至可用來擴(kuò)充PHP 語言。php 反射api 由若干類組成,可幫助我們用來訪問程序的元數(shù)據(jù)或者同相關(guān)的注釋交互。借助反射我們可以獲取諸如類實現(xiàn)了那些方法,創(chuàng)建一個類的實例(不同于用new 創(chuàng)建),調(diào)用一個方法(也不同于常規(guī)調(diào)用),傳遞參數(shù),動態(tài)調(diào)用類的靜態(tài)方法。
反射api 是php 內(nèi)建的oop 技術(shù)擴(kuò)展,包括一些類,異常和接口,綜合使用他們可用來幫助我們分析其它類,接口,方法,屬性,方法和擴(kuò)展。這些oop 擴(kuò)展被稱為反射,位于php 源碼/ext/reflection目錄下??梢允褂梅瓷鋋pi 自省反射api 本身(這可能就是反射最初的意思,自己“看”自己):
[php] view plaincopyprint
<?php
Reflection::export(new ReflectionExtension('reflection'));
?>
幾乎所有的反射api 都實現(xiàn)了reflector 接口,所有實現(xiàn)該接口的類都有一個export方法,該方法打印出參數(shù)對象的相關(guān)信息。使用get_declared_classes()獲取所有php 內(nèi)置類,get_declared_interfaces();get_defined_functions();get_defined_vars();get_defined_constants();可獲取php 接口,方法,變量,常量信息。
反射初探:
[php] view plaincopyprint
<?php
//定義一個自定義類
classMyTestClass{
public function testFunc($para0='defaultValue0'){
}
}
//接下來反射它
foreach(get_declared_classes() as $class){
//實例化一個反射類
$reflectionClass = new ReflectionClass($class);
//如果該類是自定義類
if($reflectionClass->isUserDefined()){
//導(dǎo)出該類信息
Reflection::export($reflectionClass);
}
}
?>
描述數(shù)據(jù)的數(shù)據(jù)被稱為元數(shù)據(jù),用反射獲取的信息就是元數(shù)據(jù)信息,這些信息用來描述類,接口方法等等。(元---》就是原始之意,比如元模型就是描述模型的模型,比如UML 元模型就是描述UML 結(jié)構(gòu)的模型),元數(shù)據(jù)進(jìn)一步可分為硬元數(shù)據(jù)(hardmatadata)和軟元數(shù)據(jù)(softmetadata),前者由編譯代碼導(dǎo)出,如類名字,方法,參數(shù)等。后者是人為加入的數(shù)據(jù),如phpDoc 塊,php 中的屬性等。
現(xiàn)在商業(yè)軟件很多都是基于插件架構(gòu)的,比如eclipse,和visualstudio,netbeans等一些著名IDE 都是基于插件的GUI 應(yīng)用。第三方或本方開發(fā)插件時,必須導(dǎo)入定義好的相關(guān)接口,然后實現(xiàn)這些接口,最后把實現(xiàn)的包放在指定目錄下,宿主應(yīng)用程序在啟動時自動檢測所有的插件實現(xiàn),并加載它們。如果我們自己想實現(xiàn)這樣的架構(gòu)也是可以的。
[php] view plaincopyprint
<?php
//先定義UI接口
interface IPlugin {
//獲取插件的名字
public staticfunction getName();
//要顯示的菜單項
function getMenuItems();
//要顯示的文章
function getArticles();
//要顯示的導(dǎo)航欄
function getSideBars();
}
//以下是對插件接口的實現(xiàn)
class SomePlugin implements IPlugin{
public function getMenuItems() {
//返回菜單項
return null;
}
public function getArticles() {
//返回我們的文章
return null;
}
public function getSideBars() {
//我們有一個導(dǎo)航欄
return array('SideBarItem');
}
//返回插件名
public staticfunction getName(){
return "SomePlugin";
}
}
?><span style="font-family: Arial, Verdana, sans-serif; white-space: normal; background-color: rgb(255, 255, 255); "> </span>
加載插件步驟:
1.先使用get_declared_classes()獲取所有已加載類。
2.遍歷所有類,判斷其是否實現(xiàn)了我們自定義的插件接口IPlugin。
3.獲取所有的插件實現(xiàn)。
4.在宿主應(yīng)用中與插件交互
下面這個方法幫助我們找到實現(xiàn)了插件接口的所有類:
[php] view plaincopyprint
function findPlugins() {
$plugins =array();
foreach(get_declared_classes()as $class) {
$reflectionClass= new ReflectionClass($class);
//判斷一個類是否實現(xiàn)了IPlugin 接口
if($reflectionClass->implementsInterface('IPlugin')) {
$plugins[]= $reflectionClass;
}
}
return $plugins;
}
注意到所有的插件實現(xiàn)是作為反射類實例返回的,而不是類名本身,或是類的實例。因為如果使用反射來調(diào)用方法還需要一些條件判斷。判斷一個類是否實現(xiàn)了某個方法使用反射類的hasMethod()方法。
接下來我們把所有的插件菜單項放在一個菜單上。
[php] view plaincopyprint
function integratePlugInMenus() {
$menu = array();
//遍歷所有的插件實現(xiàn)
foreach(findPlugins()as $plugin) {
//判斷插件是否實現(xiàn)了getMenuItems方法
if($plugin->hasMethod('getMenuItems')) {
/*實例化一個方法實例(注意當(dāng)你將類和方法看成概念時,它們就可以有實例,
就像“人”這個概念一樣),該方法返回的是ReflectionMethod 的實例*/
$reflectionMethod= $plugin->getMethod('getMenuItems');
//如果方法是靜態(tài)的
if($reflectionMethod->isStatic()){
//調(diào)用靜態(tài)方法,注意參數(shù)是null 而不是一個反射類實例
$items = $reflectionMethod->invoke(null);
} else {
//如果方法不是靜態(tài)的,則先實例化一個反射類實例所代表的類的實例。
$pluginInstance= $plugin->newInstance();
//使用反射api 來調(diào)用一個方法,參數(shù)是通過反射實例化的對象引用
$items= $reflectionMethod->invoke($pluginInstance);
}
//合并所有的插件菜單項為一個菜單。
$menu= array_merge($menu, $items);
}
}
return $menu;
}
這里主要用到的反射方法實例的方法調(diào)用:
public mixed invoke(stdclass object, mixedargs=null);
請一定搞清楚我們常規(guī)方法的調(diào)用是這種形式:$objRef->someMethod($argList...);
因為使用了反射,這時你在想調(diào)用一個方法時形式變?yōu)椋?div style="height:15px;">
$reflectionMethodRef->invoke($reflectionClassRef,$argList...);
如果使用反射調(diào)用方法,我們必須實例化一個反射方法的實例,如果是實例方法還要有一個實例的引用,可能還需傳遞必要的參數(shù)。當(dāng)調(diào)用一個靜態(tài)方法時,顯式傳入null 作為第一參數(shù)。對插件類實現(xiàn)的其他方法有類似的處理邏輯,這里不再敷述。
以下是我的一個簡單測試:
[php] view plaincopyprint
<?php
/**
* 定義一個插件接口
* */
interface IPlugIn
{
/**
* getSidebars()
*
* @return 返回側(cè)導(dǎo)航欄
*/
public function getSidebars();
/**
* GetName()
*
* @return 返回類名
*/
public staticfunction GetName();
}
/*下面是對插件的實現(xiàn),其實應(yīng)該放在不同的文件中,甚至是不同的包中*/
class MyPlugIn implements IPlugIn
{
public function getSidebars()
{
//構(gòu)造自己的導(dǎo)航欄
$sideBars = '<div>
<ul >
<li><ahref="">m1</a></li>
<li><ahref="">m2</a></li>
</ul>
</div>';
return $sideBars;
}
public staticfunction GetName()
{
return 'MyPlugIn';
}
}
//第二個插件實現(xiàn);
class MyPlugIn2 implements IPlugIn
{
public function getSidebars()
{
//構(gòu)造自己的導(dǎo)航欄
$sideBars = '<div><ul>
<li><ahref="">mm1</a>
</li>
<li><ahref="">mm2</a>
</li>
</ul>
</div>';
return $sideBars;
}
public staticfunction GetName()
{
return 'MyPlugIn2';
}
}
//在宿主程序中使用插件
class HostApp
{
public function initAll()
{
// 初始化各個部分
$this->renderAll();
}
//渲染GUI 格部分
function renderAll(){
$rsltSidebars="<table>";
foreach($this->integrateSidebarsOfPlugin()as $sidebarItem){
$rsltSidebars.="<tr><td>$sidebarItem</td></tr>";
}
$rsltSidebars.="</table>";
echo $rsltSidebars;
}
/*加載所有的插件實現(xiàn):*/
protectedfunction findPlugins()
{
$plugins = array();
foreach (get_declared_classes() as $class) {
$reflectionClass = new ReflectionClass($class);
if ($reflectionClass->implementsInterface('IPlugin')) {
$plugins[] = $reflectionClass;
}
}
return $plugins;
}
/**加載組裝所有插件實現(xiàn)***/
protectedfunction 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;
}
}
//運行程序:
$entryClass =new HostApp();
$entryClass->initAll();
[php] view plaincopyprint
$reflectionClass = newReflectionClass("IPlugIn");
echo  $reflectionClass->getDocComment();
這段代碼可以幫助我們獲取類的文檔注釋,一旦我們獲取了類的注釋內(nèi)容我們就可以擴(kuò)展我們的類功能,比如先獲取注釋,然后分析注釋使用docblock tokenizer 『pecl 擴(kuò)展』,或使用自帶的Tokenizer類又或者使用正則表達(dá)式,字符串函數(shù)來解析注釋文檔,你可以在注釋中加入任何東西,包括指令,在使用反射調(diào)用前可判斷這些通過注釋傳遞的指令或數(shù)據(jù):
[php] view plaincopyprint
<?php
//"分析相關(guān)的注釋數(shù)據(jù)"
analyse($reflectionClass->getDocComment());//analyse 是自己定義的?。?!
//根據(jù)分析的結(jié)果來執(zhí)行方法,或者傳遞參數(shù)等
if(xxxx){
$reflectionMethod->invoke($pluginInstance);
}
?>
因為注釋畢竟是字符串,可以使用任何字符串解析技術(shù),提取有用的信息,再根據(jù)這些信息來調(diào)用方法,就是說程序的邏輯不光可由方法實現(xiàn)決定,還可能由注釋決定(前提是你使用了反射,注釋格式嚴(yán)格有要求)。
反射api 和其他類一樣可被繼承和擴(kuò)展,所以我們可以為這些api 添加自己的功能。結(jié)合自定義注釋標(biāo)記。就是以@開頭的東東,標(biāo)注(Java 中稱為annotation),.net中稱為屬性attribute(或稱為特性)。然后擴(kuò)展Reflection 類,就可以實現(xiàn)強(qiáng)大的擴(kuò)展功能了。值得一提的是工廠方法設(shè)計模式,也常使用反射來實例化對象,下面是示例性質(zhì)的偽碼:
[php] view plaincopyprint
Class XXXFactory{
function getInstance($className){
$reflectionClass=new ReflectionClass($className);
return $reflectionClass->newInstance();
}
//使用接口的那個類實現(xiàn),可能來自配置文件
function getInstance(){
$pathOfClass= "xxx/xx/XXXImplement.php";
$className=Config->getItem($pathOfClass,'SomeClassName');
return $this->getInstance($className);
}
}
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
PHP的反射類ReflectionClass、ReflectionMethod使用實例
18道PHP網(wǎng)站開發(fā)基礎(chǔ)過關(guān)測試題
PHP設(shè)計模式之工廠方法模式
了解下PHP的Reflection反射機(jī)制
bpl插件系統(tǒng)開發(fā)
final關(guān)鍵字在PHP中的使用
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服