I have been busy writing projects recently and haven’t learned anything particularly new, so I haven’t updated my blog for a long time. Our project uses lumen, which is a lightweight framework based on laravel. I saw that some reflection API mechanisms are used to help dynamically load required classes, judgment methods, etc., so this article will be frequently used in PHP. Let me share with you the reflection API used. Students who want to learn the reflection API can take a look.
Speaking of reflection API, I feel that the reflection API in PHP is similar to the java.lang.reflect package in Java. They are both composed of a set of built-in classes that can print and analyze class member attributes and methods. Maybe you have already learned object functions such as get_class_vars(), but using the reflection API will be more flexible and the output information will be more detailed.
First of all, we need to know that the reflection API is not only used to check classes, it itself includes a set of classes to complete various functions: commonly used classes are as follows:
|
You can print basic information of the class (through the provided static export() function) | ||||||||||||
ReflectionMethod class | See the name and know the meaning, print class methods, get specific information about the method, etc. | ||||||||||||
ReflectionClass | Used to get class information, such as the methods contained in the class, the attributes of the class, whether it is an abstract class, etc. | ||||||||||||
ReflectionParameter class | Display parameter information, you can dynamically obtain the parameter transfer status of known methods | ||||||||||||
ReflectionException class | Used to display error messages | ||||||||||||
ReflectionExtension class | Get PHP extension information, you can determine whether the extension exists, etc. |
The difference between traditional printing information and reflection API
The following is a parameter program I wrote myself to demonstrate the use of reflection:
<span> 1</span> <?<span>php </span><span> 2</span> <span> 3</span> <span>class</span><span> Person </span><span> 4</span> <span>{ </span><span> 5</span> <span>//</span><span>成员属性</span> <span> 6</span> <span>public</span> <span>$name</span><span>; </span><span> 7</span> <span>public</span> <span>$age</span><span>; </span><span> 8</span> <span> 9</span> <span>//</span><span>构造方法</span> <span>10</span> <span>public</span> <span>function</span> __construct(<span>$name</span>, <span>$age</span><span>) </span><span>11</span> <span> { </span><span>12</span> <span>$this</span>->name = <span>$name</span><span>; </span><span>13</span> <span>$this</span>->age = <span>$age</span><span>; </span><span>14</span> <span> } </span><span>15</span> <span>16</span> <span>//</span><span>成员方法</span> <span>17</span> <span>public</span> <span>function</span> set_name(<span>$name</span><span>) </span><span>18</span> <span> { </span><span>19</span> <span>$this</span>-><span>$name</span> = <span>$name</span><span>; </span><span>20</span> <span> } </span><span>21</span> <span>22</span> <span>public</span> <span>function</span><span> get_name() </span><span>23</span> <span> { </span><span>24</span> <span>return</span> <span>$this</span>-><span>$name</span><span>; </span><span>25</span> <span> } </span><span>26</span> <span>27</span> <span>public</span> <span>function</span><span> get_age() </span><span>28</span> <span> { </span><span>29</span> <span>return</span> <span>$this</span>-><span>$age</span><span>; </span><span>30</span> <span> } </span><span>31</span> <span>32</span> <span>public</span> <span>function</span><span> get_user_info() </span><span>33</span> <span> { </span><span>34</span> <span>$info</span> = '姓名:' . <span>$this</span>-><span>name; </span><span>35</span> <span>$info</span> .= ' 年龄:' . <span>$this</span>-><span>age; </span><span>36</span> <span>return</span> <span>$info</span><span>; </span><span>37</span> <span> } </span><span>38</span> <span>} </span><span>39</span> <span>40</span> <span>class</span> Teacher <span>extends</span><span> Person </span><span>41</span> <span>{ </span><span>42</span> <span>private</span> <span>$salary</span> = 0<span>; </span><span>43</span> <span>44</span> <span>public</span> <span>function</span> __construct(<span>$name</span>, <span>$age</span>, <span>$salary</span><span>) </span><span>45</span> <span> { </span><span>46</span> parent::__construct(<span>$name</span>, <span>$age</span><span>); </span><span>47</span> <span>$this</span>->salary = <span>$salary</span><span>; </span><span>48</span> <span> } </span><span>49</span> <span>50</span> <span>public</span> <span>function</span><span> get_salary() </span><span>51</span> <span> { </span><span>52</span> <span>return</span> <span>$this</span>-><span>$salary</span><span>; </span><span>53</span> <span> } </span><span>54</span> <span>55</span> <span>public</span> <span>function</span><span> get_user_info() </span><span>56</span> <span> { </span><span>57</span> <span>$info</span> = parent::<span>get_user_info(); </span><span>58</span> <span>$info</span> .= " 工资:" . <span>$this</span>-><span>salary; </span><span>59</span> <span>return</span> <span>$info</span><span>; </span><span>60</span> <span> } </span><span>61</span> <span>} </span><span>62</span> <span>63</span> <span>class</span> Student <span>extends</span><span> Person </span><span>64</span> <span>{ </span><span>65</span> <span>private</span> <span>$score</span> = 0<span>; </span><span>66</span> <span>67</span> <span>public</span> <span>function</span> __construct(<span>$name</span>, <span>$age</span>, <span>$score</span><span>) </span><span>68</span> <span> { </span><span>69</span> parent::__construct(<span>$name</span>, <span>$age</span><span>); </span><span>70</span> <span>$this</span>->score = <span>$score</span><span>; </span><span>71</span> <span> } </span><span>72</span> <span>73</span> <span>public</span> <span>function</span><span> get_score() </span><span>74</span> <span> { </span><span>75</span> <span>return</span> <span>$this</span>-><span>score; </span><span>76</span> <span> } </span><span>77</span> <span>78</span> <span>public</span> <span>function</span><span> get_user_info() </span><span>79</span> <span> { </span><span>80</span> <span>$info</span> = parent::<span>get_user_info(); </span><span>81</span> <span>$info</span> .= " 成绩:" . <span>$this</span>-><span>score; </span><span>82</span> <span>return</span> <span>$info</span><span>; </span><span>83</span> <span> } </span><span>84</span> <span>} </span><span>85</span> <span>86</span> <span>header</span>("Content-type:text/html;charset=utf8;"<span>); </span><span>87</span> <span>$te_obj</span> = <span>new</span> Teacher('李老师', '36', '2000'<span>); </span><span>88</span> <span>$te_info</span> = <span>$te_obj</span>-><span>get_user_info(); </span><span>89</span> <span>90</span> <span>$st_obj</span> = <span>new</span> Student('小明', '13', '80'<span>); </span><span>91</span> <span>$st_info</span> = <span>$st_obj</span>->get_user_info();
We first use var_dump(); to print the class information, as shown below. It can be seen that only simple information of the class is printed, and there are not even methods, so no other swimming can be seen from such information. information.
var_dump($te_obj);
<span>1</span> <span>object</span>(Teacher)<span>#</span><span>1 (3) {</span> <span>2</span> ["salary":"Teacher":<span>private</span>]=> <span>3</span> <span>string</span>(4) "2000" <span>4</span> ["name"]=> <span>5</span> <span>string</span>(9) "李老师" <span>6</span> ["age"]=> <span>7</span> <span>string</span>(2) "36" <span>8</span> }
Reflection::export($obj);
We use the built-in method export provided by Reflection to print information, as shown below:
The printed information is relatively complete, including member attributes, member methods, basic information of the class, file path, method information, method attributes, parameter transfer status, the number of lines in the file, etc. A relatively comprehensive display of class information. It can be seen that var_dump() or print_r can only display brief information of the class, and a lot of information cannot be displayed at all, so they can only be used for simple debugging. The reflection API provides more information about the class, which can be a good help. We know the situation of calling classes, which provides great convenience for writing interfaces, especially calling other people's interfaces. It can also help with debugging if something goes wrong.
<span> 1</span> <span>object</span>(Teacher)<span>#</span><span>1 (3) {</span> <span> 2</span> ["salary":"Teacher":<span>private</span>]=> <span> 3</span> <span>string</span>(4) "2000" <span> 4</span> ["name"]=> <span> 5</span> <span>string</span>(9) "李老师" <span> 6</span> ["age"]=> <span> 7</span> <span>string</span>(2) "36" <span> 8</span> <span>} </span><span> 9</span> <span>Class</span> [ <span>class</span><span> Person ] { </span><span>10</span> @@ /usr/local/www/phptest/oop/reflaction.php 3-38 <span>11</span> - Constants [0<span>] { </span><span>12</span> <span> } </span><span>13</span> - <span>Static</span> properties [0<span>] { </span><span>14</span> <span> } </span><span>15</span> - <span>Static</span> methods [0<span>] { </span><span>16</span> <span> } </span><span>17</span> - Properties [2<span>] { </span><span>18</span> Property [ <span>public</span> <span>$name</span><span> ] </span><span>19</span> Property [ <span>public</span> <span>$age</span><span> ] </span><span>20</span> <span> } </span><span>21</span> <span>22</span> - Methods [5<span>] { </span><span>23</span> Method [ <span>public</span><span> method __construct ] { </span><span>24</span> @@ /usr/local/www/phptest/oop/reflaction.php 10 - 14 <span>25</span> <span>26</span> - Parameters [2<span>] { </span><span>27</span> Parameter <span>#</span><span>0 [ $name ]</span> <br />.....
Specific use of reflection API:
Anyone who has read the source code of the framework knows that the framework can load third-party plug-ins, class libraries, etc. In the following example, we use reflection API to simply implement this function. I learned the prototype of this example from a book. After understanding it, I wrote a set according to my own ideas: Function to be realized: Use a class to dynamically traverse and call the Property class Objects and classes can freely load the methods of other classes without having to embed the class into existing code or manually call the class library code.
Convention: Each class must contain a work method and can abstract an interface. You can put the information of each class in the file, which is equivalent to the information of each class library, and then call the work method of each class library through the corresponding object of the Property class library saved by the class.
The following is the basic code:
<span> 1</span> <span>/*</span><span>属性接口</span><span>*/</span> <span> 2</span> <span>interface</span><span> Property </span><span> 3</span> <span>{ </span><span> 4</span> <span>function</span><span> work(); </span><span> 5</span> <span>} </span><span> 6</span> <span> 7</span> <span>class</span><span> Person </span><span> 8</span> <span>{ </span><span> 9</span> <span>public</span> <span>$name</span><span>; </span><span>10</span> <span>public</span> <span>function</span> __construct(<span>$name</span><span>) </span><span>11</span> <span> { </span><span>12</span> <span>$this</span>->name = <span>$name</span><span>; </span><span>13</span> <span> } </span><span>14</span> <span>} </span><span>15</span> <span>16</span> <span>class</span> StudentController <span>implements</span><span> Property </span><span>17</span> <span>{ </span><span>18</span> <span>//</span><span>set方法,但需要Person对象参数</span> <span>19</span> <span>public</span> <span>function</span> setPerson(Person <span>$obj_person</span><span>) </span><span>20</span> <span> { </span><span>21</span> <span>echo</span> 'Student ' . <span>$obj_person</span>-><span>name; </span><span>22</span> <span> } </span><span>23</span> <span>24</span> <span>//</span><span>work方法简单实现</span> <span>25</span> <span>public</span> <span>function</span><span> work() </span><span>26</span> <span> { </span><span>27</span> <span>echo</span> 'student working!'<span>; </span><span>28</span> <span> } </span><span>29</span> <span>} </span><span>30</span> <span>31</span> <span>class</span> EngineController <span>implements</span><span> Property </span><span>32</span> <span>{ </span><span>33</span> <span>//</span><span>set方法</span> <span>34</span> <span>public</span> <span>function</span> setWeight(<span>$weight</span><span>) </span><span>35</span> <span> { </span><span>36</span> <span>echo</span> 'this is engine -> set weight'<span>; </span><span>37</span> <span> } </span><span>38</span> <span>39</span> <span>public</span> <span>function</span> setPrice(<span>$price</span><span>) </span><span>40</span> <span> { </span><span>41</span> <span>echo</span> "this is engine -> set price"<span>; </span><span>42</span> <span> } </span><span>43</span> <span>44</span> <span>//</span><span>work方法简单实现</span> <span>45</span> <span>public</span> <span>function</span><span> work() </span><span>46</span> <span> { </span><span>47</span> <span>echo</span> 'engine working!'<span>; </span><span>48</span> <span> } </span><span>49</span> }
Two similar classes are defined here to implement the Property interface. At the same time, they both simply implement the work() method. The StudentController class is slightly different. The parameters require Person objects. At the same time, we can use files to save the information of each class. We can also Use member attributes instead.
<span> 1</span> <span>class</span><span> Run </span><span> 2</span> <span>{ </span><span> 3</span> <span>public</span> <span>static</span> <span>$mod_arr</span> =<span> []; </span><span> 4</span> <span>public</span> <span>static</span> <span>$config</span> =<span> [ </span><span> 5</span> 'StudentController' =><span> [ </span><span> 6</span> 'person' => 'xiao ming' <span> 7</span> ], <span> 8</span> 'EngineController' =><span> [ </span><span> 9</span> 'weight' => '500kg', <span>10</span> 'price' => '4000' <span>11</span> <span> ] </span><span>12</span> <span> ]; </span><span>13</span> <span>14</span> <span>//</span><span>加载初始化</span> <span>15</span> <span>public</span> <span>function</span><span> __construct() </span><span>16</span> <span> { </span><span>17</span> <span>$config</span> = self::<span>$config</span><span>; </span><span>18</span> <span>//</span><span>用于检查是不是实现类</span> <span>19</span> <span>$property</span> = <span>new</span> ReflectionClass('Property'<span>); </span><span>20</span> <span>21</span> <span>// </span><span>22</span> <span>foreach</span> (<span>$config</span> <span>as</span> <span>$class_name</span> => <span>$params</span><span>) </span><span>23</span> <span> { </span><span>24</span> <span>$class_reflect</span> = <span>new</span> ReflectionClass(<span>$class_name</span><span>); </span><span>25</span> <span>if</span>(!<span>$class_reflect</span>->isSubclassOf(<span>$property</span><span>)) <span>//用isSubclassOf方法检查是否是这个对象 </span></span><span>26</span> <span> { </span><span>27</span> <span>echo</span> 'this is error'<span>; </span><span>28</span> <span>continue</span><span>; </span><span>29</span> <span> } </span><span>30</span> <span>31</span> <span>//</span><span>得到类的信息</span> <span>32</span> <span>$class_obj</span> = <span>$class_reflect</span>-><span>newInstance(); </span><span>33</span> <span>$class_method</span> = <span>$class_reflect</span>-><span>getMethods(); </span><span>34</span> <span>35</span> <span>foreach</span> (<span>$class_method</span> <span>as</span> <span>$method_name</span><span>) </span><span>36</span> <span> { </span><span>37</span> <span>38</span> <span>$this</span>->handle_method(<span>$class_obj</span>, <span>$method_name</span>, <span>$params</span><span>); </span><span>39</span> <span> } </span><span>40</span> <span>array_push</span>(self::<span>$mod_arr</span>, <span>$class_obj</span><span>); </span><span>41</span> <span> } </span><span>42</span> <span> } </span><span>43</span> <span>44</span> <span>//</span><span>处理方法调用</span> <span>45</span> <span>public</span> <span>function</span> handle_method(Property <span>$class_obj</span>, ReflectionMethod <span>$method_name</span>, <span>$params</span><span>) </span><span>46</span> <span> { </span><span>47</span> <span>$m_name</span> = <span>$method_name</span>-><span>getName(); </span><span>48</span> <span>49</span> <span>$args</span> = <span>$method_name</span>-><span>getParameters(); </span><span>50</span> <span>if</span>(<span>count</span>(<span>$args</span>) != 1 || <span>substr</span>(<span>$m_name</span>, 0, 3) != 'set'<span>) </span><span>51</span> <span> { </span><span>52</span> <span>return</span> <span>false</span><span>; </span><span>53</span> <span> } </span><span>54</span> <span>//大小写转换,做容错处理</span> <span>55</span> <span>$property</span> = <span>strtolower</span>(<span>substr</span>(<span>$m_name</span>, 3<span>)); </span><span>56</span> <span>57</span> <span>if</span>(!<span>isset</span>(<span>$params</span>[<span>$property</span><span>])) </span><span>58</span> <span> { </span><span>59</span> <span>return</span> <span>false</span><span>; </span><span>60</span> <span> } </span><span>61</span> <span>62</span> <span>$args_class</span> = <span>$args</span>[0]-><span>getClass(); </span><span>63</span> <span>echo</span> '<pre class="brush:php;toolbar:false">'<span>; </span><span>64</span> <span>if</span>(<span>empty</span>(<span>$args_class</span><span>)) </span><span>65</span> <span> { </span><span>66</span> <span>$method_name</span>->invoke(<span>$class_obj</span>, <span>$params</span>[<span>$property</span><span>]); <span>//如果得到的类为空证明需要传递基础类型参数 </span></span><span>67</span> } <span>else</span><span> { </span><span>68</span> <span>$method_name</span>->invoke(<span>$class_obj</span>, <span>$args_class</span>->newInstance(<span>$params</span>[<span>$property</span><span>])); <span>//如果不为空说明需要传递真实对象 </span></span><span>69</span> <span> } </span><span>70</span> <span> } </span><span>71</span> <span>} </span><span>72</span> <span>73</span> <span>//程序开始 </span><span>74</span> <span>new</span> Run();
At the end of this program, Run will automatically call the constructor method to initialize other member properties of the class library to be loaded, including initialization and execution of corresponding method operations. Here, only the corresponding set method is completed. The $mod_arr attribute saves all objects of the calling class. Each object contains data, and the included objects can be traversed to call the work() method.
The program is only used to assist in understanding reflection PAI. Each function is not perfect. It uses many reflection API classes and methods. There is a summary of each method below.
Common classes and functions provided by Reflection API:
The functions provided below are commonly used functions, not all of them. Some functions are not used at all, so we have written the ones that lie. If you want to see all of them, you can search online, there are more. There is no need to memorize the set of methods provided, you can review them when you use them.
<span> 1</span> 1<span>:Reflection </span><span> 2</span> <span>public</span> <span>static</span> export(Reflector r [,bool <span>return</span>])<span>//</span><span>打印类或方法的详细信息</span> <span> 3</span> <span>public</span> <span>static</span> getModifierNames(int modifiers) <span>//</span><span>取得修饰符的名字</span> <span> 4</span> <span> 5</span> 2<span>:ReflectionMethod: </span><span> 6</span> <span>public</span> <span>static</span> <span>string</span> export() <span>//</span><span>打印该方法的信息</span> <span> 7</span> <span>public</span> <span>mixed</span> invoke(stdclass <span>object</span>, <span>mixed</span>* args) <span>//</span><span>调用对应的方法</span> <span> 8</span> <span>public</span> <span>mixed</span> invokeArgs(stdclass <span>object</span>, <span>array</span> args)<span>//</span><span>调用对应的方法,传多参数</span> <span> 9</span> <span>public</span> bool isFinal() <span>//</span><span>方法是否为final</span> <span>10</span> <span>public</span> bool isAbstract() <span>//</span><span>方法是否为abstract</span> <span>11</span> <span>public</span> bool isPublic() <span>//</span><span>方法是否为public</span> <span>12</span> <span>public</span> bool isPrivate() <span>//</span><span>方法是否为private</span> <span>13</span> <span>public</span> bool isProtected() <span>//</span><span>方法是否为protected</span> <span>14</span> <span>public</span> bool isStatic() <span>//</span><span>方法是否为static</span> <span>15</span> <span>public</span> bool isConstructor() <span>//</span><span>方法是否为构造函数</span> <span>16</span> <span>17</span> <span>18</span> 3<span>:ReflectionClass: </span><span>19</span> <span>public</span> <span>static</span> <span>string</span> export() <span>//</span><span>打印类的详细信息</span> <span>20</span> <span>public</span> <span>string</span> getName() <span>//</span><span>取得类名或接口名</span> <span>21</span> <span>public</span> bool isInternal() <span>//</span><span>类是否为系统内部类</span> <span>22</span> <span>public</span> bool isUserDefined() <span>//</span><span>类是否为用户自定义类</span> <span>23</span> <span>public</span> bool isInstantiable() <span>//</span><span>类是否被实例化过</span> <span>24</span> <span>public</span> bool hasMethod(<span>string</span> name) <span>//</span><span>类是否有特定的方法</span> <span>25</span> <span>public</span> bool hasProperty(<span>string</span> name)<span>//</span><span>类是否有特定的属性</span> <span>26</span> <span>public</span> <span>string</span> getFileName() <span>//</span><span>获取定义该类的文件名,包括路径名</span> <span>27</span> <span>public</span> int getStartLine() <span>//</span><span>获取定义该类的开始行</span> <span>28</span> <span>public</span> int getEndLine() <span>//</span><span>获取定义该类的结束行</span> <span>29</span> <span>public</span> <span>string</span> getDocComment() <span>//</span><span>获取该类的注释</span> <span>30</span> <span>public</span> ReflectionMethod getConstructor() <span>//</span><span>取得该类的构造函数信息</span> <span>31</span> <span>public</span> ReflectionMethod getMethod(<span>string</span> name) <span> //</span><span>取得该类的某个特定的方法信息</span> <span>32</span> <span>public</span> ReflectionMethod[] getMethods() <span>//</span><span>取得该类的所有的方法信息</span> <span>33</span> <span>public</span> ReflectionProperty getProperty(<span>string</span> name) <span>//</span><span>取得某个特定的属性信息</span> <span>34</span> <span>public</span> ReflectionProperty[] getProperties() <span>//</span><span>取得该类的所有属性信息</span> <span>35</span> <span>public</span> <span>array</span> getConstants() <span>//</span><span>取得该类所有常量信息</span> <span>36</span> <span>public</span> <span>mixed</span> getConstant(<span>string</span> name) <span>//</span><span>取得该类特定常量信息</span> <span>37</span> <span>public</span> ReflectionClass[] getInterfaces() <span>//</span><span>取得接口类信息</span> <span>38</span> <span>public</span> bool isInterface() <span>//</span><span>测试该类是否为接口</span> <span>39</span> <span>public</span> bool isAbstract() <span>//</span><span>测试该类是否为抽象类</span> <span>40</span> <span>41</span> 4<span>:ReflectionParameter: </span><span>42</span> <span>public</span> <span>static</span> <span>string</span> export() <span>//</span><span>导出该参数的详细信息</span> <span>43</span> <span>public</span> <span>string</span> getName() <span>//</span><span>取得参数名</span> <span>44</span> <span>public</span> bool isPassedByReference() <span>//</span><span>测试该参数是否通过引用传递参数</span> <span>45</span> <span>public</span> ReflectionClass getClass() <span>//</span><span>若该参数为对象,返回该对象的类名</span> <span>46</span> <span>public</span> bool isArray() <span>//</span><span>测试该参数是否为数组类型</span> <span>47</span> <span>public</span> bool allowsNull() <span>//</span><span>测试该参数是否允许为空</span> <span>48</span> <span>public</span> bool isOptional() <span>//</span><span>测试该参数是否为可选的,当有默认参数时可选</span> <span>49</span> <span>public</span> bool isDefaultValueAvailable() <span>//</span><span>测试该参数是否为默认参数</span> <span>50</span> <span>public</span> <span>mixed</span> getDefaultValue() <span>//</span><span>取得该参数的默认值</span> <span>51</span> <span>52</span> 5<span>:ReflectionExtension类 </span><span>53</span> <span>54</span> <span>public</span> <span>static</span> export() <span>//</span><span>导出该扩展的所有信息</span> <span>55</span> <span>public</span> <span>string</span> getName() <span>//</span><span>取得该扩展的名字</span> <span>56</span> <span>public</span> <span>string</span> getVersion() <span>//</span><span>取得该扩展的版本</span> <span>57</span> <span>public</span> ReflectionFunction[] getFunctions() <span>//</span><span>取得该扩展的所有函数</span> <span>58</span> <span>public</span> <span>array</span> getConstants() <span>//</span><span>取得该扩展的所有常量</span> <span>59</span> <span>public</span> <span>array</span> getINIEntries() <span>//</span><span>取得与该扩展相关的,在php.ini中的指令信息</span> <span>60</span> }
I wrote it in a hurry, so there will inevitably be mistakes. Please correct me.
Please indicate the source for reprinting, thank you!