PHP API反射執行個體

來源:互聯網
上載者:User

標籤:blog   http   io   ar   os   使用   java   for   on   

*
反射是操縱物件導向範型中元模型的API,其功能十分強大,可協助我們構建複雜,可擴充的應用。其用途如:自動載入外掛程式,自動產生文檔,甚至可用來擴充PHP語言。php反射api由若干類組成,可協助我們用來訪問程式的中繼資料或者同相關的注釋互動。藉助反射我們可以擷取諸如類實現了那些方法,建立一個類的執行個體(不同於用new建立),調用一個方法(也不同於常規調用),傳遞參數,動態調用類的靜態方法。
*
**
反射api是php內建的oop技術擴充,包括一些類,異常和介面,綜合使用他們可用來協助我們分析其它類,介面,方法,屬性,方法和擴充。這些oop擴充被稱為反射,位於php源碼/ext/reflection目錄下。
可以使用反射api自省反射api本身(這可能就是反射最初的意思,自己“看”自己):

<?phpReflection::export(new ReflectionExtension(‘reflection‘));?>

幾乎所有的反射api都實現了reflector介面,所有實現該介面的類都有一個export方法,該方法列印出參數對象的相關資訊。
使用get_declared_classes()擷取所有php內建類,get_declared_interfaces();
get_defined_functions();get_defined_vars(); get_defined_constants();可擷取php介面,方法,變數,常量資訊。

反射初探:

<?php//定義一個自訂類class MyTestClass{        public function testFunc($para0=‘defaultValue0‘){            }}//接下來反射它foreach(get_declared_classes() as $class){    //執行個體化一個反射類    $reflectionClass = new ReflectionClass($class);    //如果該類是自訂類    if($reflectionClass->isUserDefined()){      //匯出該類資訊        Reflection::export($reflectionClass);    }}?>

以上片段執行個體如何查看自訂類的基本資料。
描述資料的資料被稱為中繼資料,用反射擷取的資訊就是中繼資料資訊,這些資訊用來描述類,介面方法等等。(元---》就是原始之意,比如元模型就是描述模型的模型,比如UML元模型就是描述UML結構的模型),中繼資料進一步可分為硬中繼資料(hard matadata)和軟中繼資料(soft metadata),前者由編譯代碼匯出,如類名字,方法,參數等。
後者是人為加入的資料,如phpDoc塊,php中的屬性等。


現在商業軟體很多都是基於外掛程式架構的,比如eclipse,和visual studio,netbeans等一些著名IDE都是基於外掛程式的GUI應用。第三方或本方開發外掛程式時,必須匯入定義好的相關介面,然後實現這些介面,最後把實現的包放在指定目錄下,宿主應用程式在啟動時自動檢測所有的外掛程式實現,並載入它們。如果我們自己想實現這樣的架構也是可能的。

<?php//先定義UI介面interface IPlugin {//擷取外掛程式的名字public static function getName();//要顯示的功能表項目function getMenuItems();//要顯示的文章function getArticles();//要顯示的導覽列function getSideBars();}//一下是對外掛程式介面的實現class SomePlugin implements IPlugin {public function getMenuItems() {//返回功能表項目return null;}public function getArticles() {//返回我們的文章return null;}public function getSideBars() {//我們有一個導覽列return array(‘SideBarItem‘);}//返回外掛程式名public static function getName(){return "SomePlugin";}}?>

php中也有使用外掛程式的解決方案,不像eclipse。
使用我們的外掛程式:1.先使用get_declared_classes()擷取所有已載入類。2.遍曆所有類,判斷其是否實現了我們自訂的外掛程式介面IPlugin。3.擷取所有的外掛程式實現。4.在宿主應用中與外掛程式互動

下面這個方法協助我們找到實現了外掛程式介面的所有類:

function findPlugins() {$plugins = array();foreach(get_declared_classes() as $class) {$reflectionClass = new ReflectionClass($class);//判斷一個類是否實現了IPlugin介面if($reflectionClass->implementsInterface(‘IPlugin‘)) {$plugins[] = $reflectionClass;}}return $plugins;}

注意到所有的外掛程式實現是作為反射類執行個體返回的,而不是類名本身,或是類的執行個體。因為如果使用反射來調用方法還需要一些條件判斷。
判斷一個類是否實現了某個方法使用反射類的hasMethod()方法。
接下來我們把所有的外掛程式功能表項目放在一個菜單上。

function integratePlugInMenus() {$menu = array();//遍曆所有的外掛程式實現foreach(findPlugins() as $plugin) {//判斷外掛程式是否實現了getMenuItems方法if($plugin->hasMethod(‘getMenuItems‘)) {/*執行個體化一個方法執行個體(注意當你將類和方法看成概念時,它們就可以有執行個體,就像“人”這個概念一樣),該方法返回的是ReflectionMethod的執行個體*/$reflectionMethod = $plugin->getMethod(‘getMenuItems‘);//如果方法是靜態if($reflectionMethod->isStatic()) {//調用靜態方法,注意參數是null而不是一個反射類執行個體$items = $reflectionMethod->invoke(null);} else {//如果方法不是靜態,則先執行個體化一個反射類執行個體所代表的類的執行個體。$pluginInstance = $plugin->newInstance();//使用反射api來調用一個方法,參數是通過反射執行個體化的對象引用$items = $reflectionMethod->invoke($pluginInstance);}//合并所有的外掛程式功能表項目為一個菜單。$menu = array_merge($menu, $items);}}return $menu;}

這裡主要用到的反射方法執行個體的方法調用:
public mixed invoke(stdclass object, mixed args=null);
請一定搞清楚我們常規方法的調用是這種形式:$objRef->someMethod($argList...);
因為使用了反射,這時你在想調用一個方法時形式變為:
$reflectionMethodRef->invoke($reflectionClassRef,$argList...);
如果使用反射調用方法,我們必須執行個體化一個反射方法的執行個體,如果是執行個體方法還要有一個執行個體的引用,可能還需傳遞必要的參數。當調用一個靜態方法時,顯式傳入null作為第一參數。
對外掛程式類實現的其他方法有類似的處理邏輯,這裡不再敷述。
以下是我的一個簡單測試:

<?php/*** 定義一個外掛程式介面* */interface IPlugIn{    /**     * getSidebars()     *      * @return 返回側導覽列     */    public function getSidebars();    /**     * GetName()     *      * @return 返回類名     */    public static function GetName();}/*下面是對外掛程式的實現,其實應該放在不同的檔案中,甚至是不同的包中*/class MyPlugIn implements IPlugIn{    public function getSidebars()    {        //構造自己的導覽列        $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‘;    }}//第二個外掛程式實現;class MyPlugIn2 implements IPlugIn{    public function getSidebars()    {        //構造自己的導覽列         $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()    {        // 初始化各個部分        echo "yiqing95.";     $this->renderAll();    }    //渲染GUI格部分    function renderAll(){        $rsltSidebars="<table>";        foreach($this->integrateSidebarsOfPlugin() as $sidebarItem){            $rsltSidebars.="<tr><td>$sidebarItem</td></tr>";        }        $rsltSidebars.="</table>";                echo $rsltSidebars;    }    /*載入所有的外掛程式實現:*/   protected function findPlugins()    {        $plugins = array();        foreach (get_declared_classes() as $class) {            $reflectionClass = new ReflectionClass($class);            if ($reflectionClass->implementsInterface(‘IPlugin‘)) {                $plugins[] = $reflectionClass;            }        }        return $plugins;    }    /**載入組裝所有外掛程式實現***/   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;    }    }//運行程式:$entryClass =new HostApp();$entryClass->initAll();?>

****
××××
$reflectionClass = new ReflectionClass("IPlugIn");
echo $reflectionClass-> getDocComment();
這段代碼可以協助我們擷取類的文檔注釋,一旦我們擷取了類的注釋內容我們就可以擴充我們的類功能,比如先擷取注釋,然後分析注釋使用docblock tokenizer 『pecl擴充』,或使用內建的Tokenizer類又或者使用Regex,字串函數來解析注釋文檔,你可以在注釋中加入任何東西,包括指令,在使用反射調用前可判斷這些通過注釋傳遞的指令或資料:
<?php
//"分析相關的注釋資料"
analyse($reflectionClass-> getDocComment());//analyse是自己定義的!!!
//根據分析的結果來執行方法,或者傳遞參數等
if(xxxx){
$reflectionMethod->invoke($pluginInstance) ;
}
?>
因為注釋畢竟是字串,可以使用任何字串解析技術,提取有用的資訊,再根據這些資訊來調用方法,就是說程式的邏輯不光可由方法實現決定,還可能由注釋決定(前提是你使用了反射,注釋格式嚴格有要求)。

反射api和其他類一樣可被繼承擴充,所以我們可以為這些api添加自己的功能。結合自訂注釋標記。就是以@開頭的東東,標註(Java中稱為annotation),.net中稱為屬性attribute(或稱為特性)。然後擴充Reflection類,就可以實現強大的擴充功能了。
值得一提的是Factory 方法設計模式(GOF之一),也常使用反射來執行個體化對象,下面是樣本性質的偽碼:

Class XXXFactory{function getInstance($className){   $reflectionClass =new ReflectionClass($className);   return $reflectionClass->newInstance();    }//使用介面的那個類實現,可能來自設定檔function getInstance(){$pathOfConfig = "xxx/xx/XXXImplement.php";$className= Config->getItem($pathOfClass,‘SomeClassName‘);return $this->getInstance($className); }} 
轉載:http://blog.csdn.net/siren0203/article/details/5994571

PHP API反射執行個體

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.