PHP反射API

  近期忙着寫項目,沒有學習什麼特別新的東西,因此好長時間沒有更新博客。咱們的項目用的是lumen,是基於laravel的一個輕量級框架,我看到裏面用到了一些反射API機制來幫助動態加載須要的類、判斷方法等,因此本篇文章就把在PHP中常常用到的反射API給你們分享一下吧,想學習反射API的同窗能夠看看。php

  提及反射ApI,自我感受PHP中的反射ApI和java中的java.lang.reflect包差很少,都是由能夠打印和分析類成員屬性、方法的一組內置類組成的。可能你已經學習過對象函數好比:get_class_vars()可是使用反射API會更加的靈活、輸出信息會更加詳細。html

  首先咱們須要知道,反射API不只僅是用來檢查類的,它自己包括一組類,用來完成各類功能:經常使用的類以下:java

Reflection類 能夠打印類的基本信息,(經過提供的靜態export()函數)
ReflectionMethod類 見名知意,打印類方法、獲得方法的具體信息等
ReflectionClass類 用於獲得類信息,好比獲得類包含的方法,類本的屬性,是否是抽象類等
ReflectionParameter類 顯示參數的信息,能夠動態獲得已知方法的傳參狀況
ReflectionException類  用於顯示錯誤信息
ReflectionExtension類 獲得PHP的擴展信息,能夠判斷擴展是否存在等

 

 

 

 

 

 

 

 

傳統的打印類信息與反射APi的區別
下面是一段我本身寫的參數程序,用於演示反射的使用:laravel

 1 <?php
 2 
 3 class Person
 4 {
 5     //成員屬性
 6     public $name;
 7     public $age; 
 8 
 9     //構造方法
10     public function __construct($name, $age)
11     {
12         $this->name = $name;
13         $this->age = $age;
14     }
15 
16     //成員方法
17     public function set_name($name)
18     {
19         $this->$name = $name;
20     }
21 
22     public function get_name()
23     {
24         return $this->$name;
25     }
26 
27     public function get_age()
28     {
29         return $this->$age;
30     }
31 
32     public function get_user_info()
33     {
34         $info = '姓名:' . $this->name;
35         $info .= ' 年齡:' . $this->age;
36         return $info;
37     }
38 }
39 
40 class Teacher extends Person
41 {
42     private $salary = 0;
43 
44     public function __construct($name, $age, $salary)
45     {
46         parent::__construct($name, $age);
47         $this->salary = $salary;
48     }
49 
50     public function get_salary()
51     {
52         return $this->$salary;
53     }
54 
55     public function get_user_info()
56     {
57         $info = parent::get_user_info();
58         $info .= " 工資:" . $this->salary;
59         return $info;
60     }
61 }
62 
63 class Student extends Person
64 {
65     private $score = 0;
66 
67     public function __construct($name, $age, $score)
68     {
69         parent::__construct($name, $age);
70         $this->score = $score;
71     }
72 
73     public function get_score()
74     {
75         return $this->score;        
76     }
77 
78     public function get_user_info()
79     {
80         $info = parent::get_user_info();
81         $info .= " 成績:" . $this->score;
82         return $info;
83     }
84 }
85 
86 header("Content-type:text/html;charset=utf8;");
87 $te_obj = new Teacher('李老師', '36', '2000');
88 $te_info = $te_obj->get_user_info();
89 
90 $st_obj = new Student('小明', '13', '80');
91 $st_info = $st_obj->get_user_info();

咱們先用var_dump();打印類的信息,以下所示,能夠看出只是打印出類的簡單信息,甚至連方法也沒有,因此從這樣的信息中看不出其餘游泳的信息。數組

var_dump($te_obj);框架

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

  Reflection::export($obj);函數

  咱們利用Reflection提供的內置方法export來打印信息,以下所示:oop

  打印出的信息比較完整,包括成員屬性,成員方法,類的基本信息,文件路徑,方法信息,方法屬性,傳參狀況,所在文件的行數等等。比較全面的展現了類的信息。能夠看出var_dump()或者print_r只能顯示類的簡要信息,好多信息根本顯示不出來,因此他們只能作簡單的調試之用,反射Api則提供的類更多的信息,能夠很好地幫助咱們知道調用類的狀況,這對寫接口,特別是調用別人的接口提供了極大的便利。若是出了問題,也能夠幫助調試。學習

 1 object(Teacher)#1 (3) {
 2       ["salary":"Teacher":private]=>
 3           string(4) "2000"
 4       ["name"]=>
 5           string(9) "李老師"
 6       ["age"]=>
 7           string(2) "36"
 8 }
 9 Class [  class Person ] {
10       @@ /usr/local/www/phptest/oop/reflaction.php 3-38
11       - Constants [0] {
12       }
13       - Static properties [0] {
14       }
15       - Static methods [0] {
16  }
17   - Properties [2] {
18         Property [  public $name ]
19         Property [  public $age ]
20   }
21 
22   - Methods [5] {
23     Method [  public method __construct ] {
24       @@ /usr/local/www/phptest/oop/reflaction.php 10 - 14
25 
26       - Parameters [2] {
27         Parameter #0 [  $name ]

.....

反射API的具體使用:測試

  看過框架源碼的同窗都知道框架均可以加載第三方的插件、類庫等等。下面這個例子我們藉助反射APi簡單實現這個功能,該例子原型是我從書上學習的,我理解後按照本身的思路寫了一套:要實現的功能:用一個類去動態的遍歷調用Property類對象,類能夠自由的加載其餘的類的方法,而不用吧類嵌入到已有的代碼,也不用手動去調用類庫的代碼。
    約定:每個類要包含work方法,能夠抽象出一個接口。能夠把每一個類的信息放在文件中,至關於各個類庫信息,經過類保存的Property類庫的對應對象,而後調用每一個類庫的work方法。

  下面是基礎代碼:

 1 /*屬性接口*/
 2 interface Property
 3 {
 4     function work();
 5 }
 6 
 7 class Person
 8 {
 9     public $name;
10     public function __construct($name)
11     {
12         $this->name = $name;
13     }
14 }
15 
16 class StudentController implements Property
17 {
18     //set方法,但須要Person對象參數
19     public function setPerson(Person $obj_person)
20     {
21         echo 'Student ' . $obj_person->name;
22     }
23 
24     //work方法簡單實現
25     public function work()
26     {
27         echo 'student working!';
28     }
29 }
30 
31 class EngineController implements Property
32 {
33     //set方法
34     public function setWeight($weight)
35     {
36         echo 'this is engine -> set weight';
37     }
38 
39     public function setPrice($price)
40     {
41         echo "this is engine -> set price";
42     }
43 
44     //work方法簡單實現
45     public function work()
46     {
47         echo 'engine working!';
48     }
49 }

    這裏定義了兩個類似類實現Property接口,同時都簡單實現work()方法 StudentController類稍微不一樣,參數須要Person對象,同時咱們可使用文件來保存各個類的信息,咱們也能夠用成員屬性代替。

 1 class Run
 2 {
 3     public static $mod_arr = [];
 4     public static $config = [
 5         'StudentController' => [
 6             'person' => 'xiao ming'
 7         ],
 8         'EngineController'  => [
 9             'weight' => '500kg',
10             'price'  => '4000'
11         ]
12     ];
13 
14     //加載初始化
15     public function __construct()
16     {
17         $config = self::$config;
18         //用於檢查是否是實現類
19         $property = new ReflectionClass('Property');
20         foreach ($config as $class_name => $params) {
21             $class_reflect = new ReflectionClass($class_name);
22             if(!$class_reflect->isSubclassOf($property)) {//用isSubclassOf方法檢查是不是這個對象
23                 echo 'this is  error';
24                 continue;
25             }
26 
27             //獲得類的信息
28             $class_obj = $class_reflect->newInstance();
29             $class_method = $class_reflect->getMethods();
30 
31             foreach ($class_method as $method_name) {
32                 $this->handle_method($class_obj, $method_name, $params);
33             }
34             array_push(self::$mod_arr, $class_obj);
35         }
36     }
37 
38     //處理方法調用
39     public function handle_method(Property $class_obj, ReflectionMethod $method_name, $params)
40     {
41         $m_name = $method_name->getName();
42         $args = $method_name->getParameters();
43 
44         if(count($args) != 1 || substr($m_name, 0, 3) != 'set') {    
45             return false;
46         }
47         //大小寫轉換,作容錯處理
48         $property = strtolower(substr($m_name, 3));
49      
50         if(!isset($params[$property])) {
51             return false;
52         }
53 
54         $args_class = $args[0]->getClass();
55         echo '<pre>';
56         if(empty($args_class)) {
57             $method_name->invoke($class_obj, $params[$property]); //若是獲得的類爲空證實須要傳遞基礎類型參數
58         } else {
59             $method_name->invoke($class_obj, $args_class->newInstance($params[$property])); //若是不爲空說明須要傳遞真實對象
60         }
61     }
62 }
63 
64 //程序開始
65 new Run();

  到此程序結束,Run啓動會自動調用構造方法,初始化要加載類庫的其餘成員屬性,包括初始化和執行相應方法操做,這裏只是完成了對應的set方法。其中$mod_arr屬性保存了全部調用類的對象,每一個對象包含數據,能夠遍歷包含的對象來以此調用work()方法。

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

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

下面提供的函數是經常使用的函數,不是所有,有的函數根本用不到,因此咱們有往撒謊那個寫,想看所有的能夠到網上搜一下,比較多。提供的這組方法沒有必要背下來,用到的時候能夠查看。

 1 1:Reflection
 2   public static export(Reflector r [,bool return])//打印類或方法的詳細信息
 3   public static  getModifierNames(int modifiers)  //取得修飾符的名字
 4 
 5 2:ReflectionMethod:
 6     public static string export()                       //打印該方法的信息
 7     public mixed invoke(stdclass object, mixed* args)   //調用對應的方法
 8     public mixed invokeArgs(stdclass object, array args)//調用對應的方法,傳多參數
 9     public bool isFinal()        //方法是否爲final
10     public bool isAbstract()     //方法是否爲abstract
11     public bool isPublic()       //方法是否爲public
12     public bool isPrivate()      //方法是否爲private
13     public bool isProtected()    //方法是否爲protected
14     public bool isStatic()       //方法是否爲static
15     public bool isConstructor()  //方法是否爲構造函數
17 
18 3:ReflectionClass:
19     public static string export()  //打印類的詳細信息
20     public string getName()        //取得類名或接口名
21     public bool isInternal()       //類是否爲系統內部類
22     public bool isUserDefined()    //類是否爲用戶自定義類
23     public bool isInstantiable()   //類是否被實例化過
24     public bool hasMethod(string name)  //類是否有特定的方法
25     public bool hasProperty(string name)//類是否有特定的屬性
26     public string getFileName()         //獲取定義該類的文件名,包括路徑名
27     public int getStartLine()           //獲取定義該類的開始行
28     public int getEndLine()             //獲取定義該類的結束行
29     public string getDocComment()       //獲取該類的註釋
30     public ReflectionMethod getConstructor()           //取得該類的構造函數信息
31     public ReflectionMethod getMethod(string name)     //取得該類的某個特定的方法信息
32     public ReflectionMethod[] getMethods()             //取得該類的全部的方法信息
33     public ReflectionProperty getProperty(string name) //取得某個特定的屬性信息
34     public ReflectionProperty[] getProperties()        //取得該類的全部屬性信息
35     public array getConstants()                        //取得該類全部常量信息
36     public mixed getConstant(string name)              //取得該類特定常量信息
37     public ReflectionClass[] getInterfaces()           //取得接口類信息
38     public bool isInterface()  //測試該類是否爲接口
39     public bool isAbstract()   //測試該類是否爲抽象類
40 
41 4:ReflectionParameter:
42     public static string export()     //導出該參數的詳細信息
43     public string getName()           //取得參數名
44     public bool isPassedByReference() //測試該參數是否經過引用傳遞參數
45     public ReflectionClass getClass() //若該參數爲對象,返回該對象的類名
46     public bool isArray()             //測試該參數是否爲數組類型
47     public bool allowsNull()          //測試該參數是否容許爲空
48     public bool isOptional()          //測試該參數是否爲可選的,當有默認參數時可選
49     public bool isDefaultValueAvailable() //測試該參數是否爲默認參數
50     public mixed getDefaultValue()        //取得該參數的默認值
51 
52 5:ReflectionExtension類
54     public static  export()    //導出該擴展的全部信息
55     public string getName()    //取得該擴展的名字
56     public string getVersion() //取得該擴展的版本
57     public ReflectionFunction[] getFunctions()   //取得該擴展的全部函數
58     public array getConstants()  //取得該擴展的全部常量
59     public array getINIEntries() //取得與該擴展相關的,在php.ini中的指令信息
60 }

寫的比較急,不免會有錯誤,還請大神們多多指正。

轉載請註明出處:http://www.cnblogs.com/zyf-zhaoyafei/p/4922893.html

本博客同步更新到個人我的網站:www.zhaoyafei.cn

相關文章
相關標籤/搜索