php反射API 簡單教程

來源:互聯網
上載者:User
說起反射ApI,自我感覺PHP中的反射ApI和java中的java.lang.reflect包差不多,都是由可以列印和分析類成員屬性、方法的一組內建類組成的。可能你已經學習過對象函數比如:get_class_vars()但是使用反射API會更加的靈活、輸出資訊會更加詳細。

  首先我們需要知道,反射API不僅僅是用來檢查類的,它本身包括一組類,用來完成各種功能:常用的類如下:

Reflection類 可以列印類的基本資料,(通過提供的靜態export()函數)
ReflectionMethod類 見名知意,列印類方法、得到方法的具體資訊等
ReflectionClass類 用於得到類資訊,比如得到類包含的方法,類本的屬性,是不是抽象類別等
ReflectionParameter類 顯示參數的資訊,可以動態得到已知方法的傳參情況
ReflectionException類 用於顯示錯誤資訊
ReflectionExtension類 得到PHP的擴充資訊,可以判斷擴充是否存在等






傳統的列印類資訊與反射APi的區別
下面是一段我自己寫的參數程式,用於示範反射的使用:

<?phpclass Person{    //成員屬性    public $name;    public $age;     //構造方法    public function construct($name, $age)    {        $this->name = $name;        $this->age = $age;    }    //成員方法    public function set_name($name)    {        $this->$name = $name;    }    public function get_name()    {        return $this->$name;    }    public function get_age()    {        return $this->$age;    }    public function get_user_info()    {        $info = '姓名:' . $this->name;        $info .= ' 年齡:' . $this->age;        return $info;    }}class Teacher extends Person{    private $salary = 0;    public function construct($name, $age, $salary)    {        parent::construct($name, $age);        $this->salary = $salary;    }    public function get_salary()    {        return $this->$salary;    }    public function get_user_info()    {        $info = parent::get_user_info();        $info .= " 工資:" . $this->salary;        return $info;    }}class Student extends Person{    private $score = 0;    public function construct($name, $age, $score)    {        parent::construct($name, $age);        $this->score = $score;    }    public function get_score()    {        return $this->score;            }    public function get_user_info()    {        $info = parent::get_user_info();        $info .= " 成績:" . $this->score;        return $info;    }}header("Content-type:text/html;charset=utf8;");$te_obj = new Teacher('李老師', '36', '2000');$te_info = $te_obj->get_user_info();$st_obj = new Student('小明', '13', '80');$st_info = $st_obj->get_user_info();

我們先用var_dump();列印類的資訊,如下所示,可以看出只是列印出類的簡單資訊,甚至連方法也沒有,所以從這樣的資訊中看不出其他遊泳的資訊。

var_dump($te_obj);

object(Teacher)#1 (3) {      ["salary":"Teacher":private]=>          string(4) "2000"      ["name"]=>          string(9) "李老師"      ["age"]=>          string(2) "36"}

  Reflection::export($obj);

  我們利用Reflection提供的內建方法export來列印資訊,如下所示:

  列印出的資訊比較完整,包括成員屬性,成員方法,類的基本資料,檔案路徑,方法資訊,方法屬性,傳參情況,所在檔案的行數等等。比較全面的展示了類的資訊。可以看出var_dump()或者print_r只能顯示類的簡要資訊,好多資訊根本顯示不出來,所以他們只能做簡單的調試之用,反射Api則提供的類更多的資訊,可以很好地協助我們知道調用類的情況,這對寫介面,特別是調用別人的介面提供了極大的便利。如果出了問題,也可以協助調試。

object(Teacher)#1 (3) {      ["salary":"Teacher":private]=>          string(4) "2000"      ["name"]=>          string(9) "李老師"      ["age"]=>          string(2) "36"}Class [  class Person ] {      @@ /usr/local/www/phptest/oop/reflaction.php 3-38      - Constants [0] {      }      - Static properties [0] {      }      - Static methods [0] { }  - Properties [2] {        Property [  public $name ]        Property [  public $age ]  }  - Methods [5] {    Method [  public method construct ] {      @@ /usr/local/www/phptest/oop/reflaction.php 10 - 14      - Parameters [2] {        Parameter #0 [  $name ].....

反射API的具體使用:

  看過架構源碼的同學都知道架構都可以載入第三方的外掛程式、類庫等等。下面這個例子咱們藉助反射APi簡單實現這個功能,該例子原型是我從書上學習的,我理解後按照自己的思路寫了一套:要實現的功能:用一個類去動態遍曆調用Property類對象,類可以自由的載入其他的類的方法,而不用吧類嵌入到已有的代碼,也不用手動去調用類庫的代碼。
約定:每一個類要包含work方法,可以抽象出一個介面。可以把每個類的資訊放在檔案中,相當於各個類庫資訊,通過類儲存的Property類庫的對應對象,然後調用每個類庫的work方法。

下面是基礎代碼:

/*屬性介面*/interface Property{    function work();}class Person{    public $name;    public function construct($name)    {        $this->name = $name;    }}class StudentController implements Property{    //set方法,但需要Person對象參數    public function setPerson(Person $obj_person)    {        echo 'Student ' . $obj_person->name;    }    //work方法簡單實現    public function work()    {        echo 'student working!';    }}class EngineController implements Property{    //set方法    public function setWeight($weight)    {        echo 'this is engine -> set weight';    }    public function setPrice($price)    {        echo "this is engine -> set price";    }    //work方法簡單實現    public function work()    {        echo 'engine working!';    }}

這裡定義了兩個相似類實現Property介面,同時都簡單實現work()方法 StudentController類稍微不同,參數需要Person對象,同時我們可以使用檔案來儲存各個類的資訊,我們也可以用成員屬性代替。

class Run{    public static $mod_arr = [];    public static $config = [        'StudentController' => [            'person' => 'xiao ming'        ],        'EngineController'  => [            'weight' => '500kg',            'price'  => '4000'        ]    ];    //載入初始化    public function construct()    {        $config = self::$config;        //用於檢查是不是實作類別        $property = new ReflectionClass('Property');        foreach ($config as $class_name => $params) {            $class_reflect = new ReflectionClass($class_name);            if(!$class_reflect->isSubclassOf($property)) {//用isSubclassOf方法檢查是否是這個對象                echo 'this is  error';                continue;            }            //得到類的資訊            $class_obj = $class_reflect->newInstance();            $class_method = $class_reflect->getMethods();            foreach ($class_method as $method_name) {                $this->handle_method($class_obj, $method_name, $params);            }            array_push(self::$mod_arr, $class_obj);        }    }    //處理方法調用    public function handle_method(Property $class_obj, ReflectionMethod $method_name, $params)    {        $m_name = $method_name->getName();        $args = $method_name->getParameters();        if(count($args) != 1 || substr($m_name, 0, 3) != 'set') {                return false;        }        //大小寫轉換,做容錯處理        $property = strtolower(substr($m_name, 3));             if(!isset($params[$property])) {            return false;        }        $args_class = $args[0]->getClass();        echo '<pre>';        if(empty($args_class)) {            $method_name->invoke($class_obj, $params[$property]); //如果得到的類為空白證明需要傳遞基礎型別參數        } else {            $method_name->invoke($class_obj, $args_class->newInstance($params[$property])); //如果不為空白說明需要傳遞真實對象        }    }}//程式開始new Run();

  到此程式結束,Run啟動會自動調用構造方法,初始化要載入類庫的其他成員屬性,包括初始化和執行相應方法操作,這裡只是完成了對應的set方法。其中$mod_arr屬性儲存了所有調用類的對象,每個對象包含資料,可以遍曆包含的對象來以此調用work()方法。

  程式只做輔助理解反射PAI用,各個功能沒有完善,裡面用到了好多反射API的類,方法,下面會有各個方法的總結。

反射API提供的常用類和函數:

下面提供的函數是常用的函數,不是全部,有的函數根本用不到,所以我們有往撒謊那個寫,想看全部的可以到網上搜一下,比較多。提供的這組方法沒有必要背下來,用到的時候可以查看。

1:Reflection  public static export(Reflector r [,bool return])//列印類或方法的詳細資料  public static  getModifierNames(int modifiers)  //取得修飾符的名字2:ReflectionMethod:    public static string export()                       //列印該方法的資訊    public mixed invoke(stdclass object, mixed* args)   //調用對應的方法    public mixed invokeArgs(stdclass object, array args)//調用對應的方法,傳多參數    public bool isFinal()        //方法是否為final    public bool isAbstract()     //方法是否為abstract    public bool isPublic()       //方法是否為public    public bool isPrivate()      //方法是否為private    public bool isProtected()    //方法是否為protected    public bool isStatic()       //方法是否為static    public bool isConstructor()  //方法是否為建構函式3:ReflectionClass:    public static string export()  //列印類的詳細資料    public string getName()        //取得類名或介面名    public bool isInternal()       //類是否為系統內部類    public bool isUserDefined()    //類是否為使用者自訂類    public bool isInstantiable()   //類是否被執行個體化過    public bool hasMethod(string name)  //類是否有特定的方法    public bool hasProperty(string name)//類是否有特定的屬性    public string getFileName()         //擷取定義該類的檔案名稱,包括路徑名    public int getStartLine()           //擷取定義該類的開始行    public int getEndLine()             //擷取定義該類的結束行    public string getDocComment()       //擷取該類的注釋    public ReflectionMethod getConstructor()           //取得該類的建構函式資訊    public ReflectionMethod getMethod(string name)     //取得該類的某個特定的方法資訊    public ReflectionMethod[] getMethods()             //取得該類的所有的方法資訊    public ReflectionProperty getProperty(string name) //取得某個特定的屬性資訊    public ReflectionProperty[] getProperties()        //取得該類的所有屬性資訊    public array getConstants()                        //取得該類所有常量資訊    public mixed getConstant(string name)              //取得該類特定常量資訊    public ReflectionClass[] getInterfaces()           //取得介面類資訊    public bool isInterface()  //測試該類是否為介面    public bool isAbstract()   //測試該類是否為抽象類別4:ReflectionParameter:    public static string export()     //匯出該參數的詳細資料    public string getName()           //取得參數名    public bool isPassedByReference() //測試該參數是否通過引用傳遞參數    public ReflectionClass getClass() //若該參數為對象,返回該對象的類名    public bool isArray()             //測試該參數是否為數群組類型    public bool allowsNull()          //測試該參數是否允許為空白    public bool isOptional()          //測試該參數是否為可選的,當有預設參數時可選    public bool isDefaultValueAvailable() //測試該參數是否為預設參數    public mixed getDefaultValue()        //取得該參數的預設值5:ReflectionExtension類    public static  export()    //匯出該擴充的所有資訊    public string getName()    //取得該擴充的名字    public string getVersion() //取得該擴充的版本    public ReflectionFunction[] getFunctions()   //取得該擴充的所有函數    public array getConstants()  //取得該擴充的所有常量    public array getINIEntries() //取得與該擴充相關的,在php.ini中的指令資訊}

聯繫我們

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