詳解PHP反射技術的程式碼範例(圖文)

來源:互聯網
上載者:User

摘要

相比於Java的反射,PHP中的反射可真的是良心之作。雖然從維護的角度來看,Java更勝一籌也更有優勢。但是繁瑣的處理也為Java的反射機制增加了一定的學習成本。

今天嘗試著使用PHP的反射技術來擷取類的資訊。
核心操作可以在PHP的官方協助文檔上看到,這裡用得最多的就是

getPropertiesgetMethods

目標類

為了更好的示範反射的結果以及維護,下面就先建立一個類,目錄結構如下:

<?phpclass Person {    private $name;    private $age;    private $address;    public function __construct($name, $age, $address) {        $this->name = $name;        $this->age = $age;        $this->address = $address;    }    public function setter($key, $value) {        exec ( "{$this}->" . $key . "={$value}" );    }    /**     * 通配型的getter方法不好用。     * <br />     * 原因: Object Person can not be converted to string.     *      * @param unknown $key              * @return string     */    public function getter($key) {        return exec ( "$this" . "->{$key}" );    }    /**     * 類比Java語言實現的getter方法。<br />     *     * 缺點: 需要為每一個private屬性提供單獨的getter方法,使得代碼略顯臃腫。     */    public function getName() {        return $this->name;    }}class Grade {    private $name;    public function __construct($name) {        $this->name = $name;    }    public function setName($name) {        $this->name = $name;    }    public function getName() {        return $this->name;    }}

載入問題

載入機制

在正式進行反射操作之前,先來探討一下__autoload自動載入機制。顧名思義,自動化的進行載入(類,也可以是其他php檔案)唄。

對於更深層次而言,這就涉及到PHP解譯器的工作原理了。也就是說,我們不可能一個項目唯寫一個php檔案,相反,一個項目中可能會有數以百計的php檔案,而且不可避免的會進行相互調用。

也就是說,我們在A檔案中聲明並實現了一個加法函數,而需要在B檔案中進行調用。很明顯B檔案中根本沒有實現這個加法,所以PHP解譯器就沒辦法進行加法運算了。

這個時候就需要讓PHP解譯器知道這個加法怎麼做,於是就需要require / include 包含了這個加法函數的A檔案了。

這樣,PHP解譯器就知道如何解釋並運行咱們的PHP檔案了。

與PHP相似的是,在Java語言中我們只需要在源檔案前面添加import語句,Java虛擬機器就能自動的在相關的類資訊了。而且強型別的Java可以在編譯之前就發現這樣的問題,所以代碼維護起來比較方便一點。而PHP則需要進行手動的 include/require了。

但是應該清楚的是,這兩者換湯不換藥而已。

自動載入機制

但是如果對每一個要被引用的php檔案進行手動的載入的話,可能就要寫好多個這樣的載入語句了。所以為了方便處理這種問題,PHP5之後引入了自動載入機制。

void __autoload ( string $class )

$class 就是要進行載入的類的名稱,請注意是類的名稱。

怎麼使用?

既然自動載入機制這麼好,那麼我們要怎麼使用呢?

答案就是在需要載入其他類檔案的php中,添加一個自訂的__autoload($class) 函數即可。 還是以剛才的檔案AB來舉例。

檔案A中有一個寫好的類Person,在檔案B中要進行使用。這個時候在檔案B中添加一個__aotoload函數即可。而且這個函數的寫法也比較的簡單(一切按照最簡思路來設計的話)。

function __autoload($class) {    $filename = "$class.class.php";        if(!file_exists($filename)){            throw new RuntimeException("$filename 檔案不存在!");    }else {        require "$filename";    }}

PHP解譯器在掃描到檔案B的時候會先進行檢查,如果未引入目標類Person,則會判斷有沒有實現__autoload,如果存在則使用自動載入函數進行載入,否則報錯退出。

注意問題

雖然上面的自動載入函數比較簡單,但是現實中卻需要為此付出很多的“代價”,也就是被載入的類檔案的名稱要和類保持一致(無需區分大小寫)。如:

要載入的類的名稱為Person,則該類所在的檔案的名稱需要為person.class.php,或者Person.class.php

而且,路徑問題也是一個比較棘手的問題,在這個簡易的自動載入函數中也不難看到,這裡他們位於同級目錄下,試想一下不滿足這個條件的情形,就可以知道這個自動載入函數的代碼量將會多麼大了吧。

如此的話,也會違反了自動載入機制的設計的初衷。所以按照特定的目錄結構存放相關的類檔案是非常有必要的。

所謂:增加了冗餘的特點,卻帶來了容易維護的好處。

個人覺得,不妨按照Java語言的目錄結構來維護PHP程式,這樣會有意想不到的收穫的。

反射

下面正式進入反射的話題,在摘要部分已經提到。重點就在於ReflectionClass的使用。

反射屬性

<?phprequire './bean/beans.php';// Person 在beans.php檔案中聲明$protype = new ReflectionClass("Person");// 可以添加一個參數,來進行過濾操作。如只擷取public類型的屬性$properties = $protype->getProperties();// 反射擷取到類的屬性資訊foreach ($properties as $property) {    echo $property."<br />";}

相比於Java,要擷取 private屬性,PHP更為簡單。

反射方法

<?phprequire './bean/beans.php';$protype = new ReflectionClass("Person");$methods = $protype->getMethods();foreach ($methods as $method) {    echo $method->getName()."<br />";}

另外,還可以添加過濾條件。給getMethods方法天機一個過濾參數即可。

filter過濾結果為僅包含某些屬性的方法。預設不過濾。 ReflectionMethod::IS_STATIC、 ReflectionMethod::IS_PUBLIC、 ReflectionMethod::IS_PROTECTED、 ReflectionMethod::IS_PRIVATE、 ReflectionMethod::IS_ABSTRACT、 ReflectionMethod::IS_FINAL 的任意組合。

反射注釋

注釋資訊,這裡就以文檔資訊為例。

<?phprequire './bean/beans.php';$protype = new ReflectionClass ( "Person" );$properties = $protype->getProperties ();// 反射擷取到類的屬性資訊foreach ( $properties as $property ) {    echo $property . ":";    $doc = $property->getDocComment ();    echo "&nbsp;&nbsp;&nbsp;" . $doc . "<br />";    echo "--------------------------------------------------------" . "<br />";}$methods = $protype->getMethods();foreach ($methods as $method) {    echo $method->getName()."<br />";    $doc = $method->getDocComment ();     echo "&nbsp;&nbsp;&nbsp;" . $doc . "<br />";     echo "--------------------------------------------------------" . "<br />";}

反射執行個體化

反射Person類

<?phprequire './bean/beans.php';$protype = new ReflectionClass ( "Person" );// 類比資料庫中擷取到的值,以關聯陣列的形式拋出$values = array(    "name"=>"郭璞",    "age"=> 21,    "address"=>"遼寧省大連市");// 開始執行個體化$instance = $protype->newInstanceArgs($values);    print_r($instance);// var_dump($instance);echo $instance->getName();

反射Grade類

<?phprequire './bean/beans.php';$classprotype = new ReflectionClass("Grade");$class = $classprotype->newInstanceArgs(array("name"=>"大三"));var_dump($class);echo $class->getName();

執行類的方法

$instance->getName(); // 執行Person 裡的方法getName// 或者:$method = $class->getmethod('getName'); // 擷取Person 類中的getName方法$method->invoke($instance);    // 執行getName 方法// 或者:$method = $class->getmethod('setName'); // 擷取Person 類中的setName方法$method->invokeArgs($instance, array('snsgou.com'));

總結

回顧一下,本次實驗示範了PHP中的反射技術,對比分析了Java語言的反射技術的實現。也只能說各有利弊吧。

在Java中,反射技術是編寫架構的基礎。雖然在PHP中反射技術不是特別的重要,而且用的時候約束也比較多,稍顯雞肋。但是比葫蘆畫瓢的話,還是可以做出一些有用的小工具的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.