近期忙着寫項目,沒有學習什麼特別新的東西,因此好長時間沒有更新博客。咱們的項目用的是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