Maison > Article > développement back-end > PHP反射API,反射api_PHP教程
近期忙着写项目,没有学习什么特别新的东西,所以好长时间没有更新博客。我们的项目用的是lumen,是基于laravel的一个轻量级框架,我看到里面用到了一些反射API机制来帮助动态加载需要的类、判断方法等,所以本篇文章就把在PHP中经常用到的反射API给大家分享一下吧,想学习反射API的同学可以看看。
说起反射ApI,自我感觉PHP中的反射ApI和java中的java.lang.reflect包差不多,都是由可以打印和分析类成员属性、方法的一组内置类组成的。可能你已经学习过对象函数比如:get_class_vars()但是使用反射API会更加的灵活、输出信息会更加详细。
首先我们需要知道,反射API不仅仅是用来检查类的,它本身包括一组类,用来完成各种功能:常用的类如下:
Reflection类 | 可以打印类的基本信息,(通过提供的静态export()函数) |
ReflectionMethod类 | 见名知意,打印类方法、得到方法的具体信息等 |
ReflectionClass类 | 用于得到类信息,比如得到类包含的方法,类本的属性,是不是抽象类等 |
ReflectionParameter类 | 显示参数的信息,可以动态得到已知方法的传参情况 |
ReflectionException类 | 用于显示错误信息 |
ReflectionExtension类 | 得到PHP的扩展信息,可以判断扩展是否存在等 |
传统的打印类信息与反射APi的区别
下面是一段我自己写的参数程序,用于演示反射的使用:
<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();
我们先用var_dump();打印类的信息,如下所示,可以看出只是打印出类的简单信息,甚至连方法也没有,所以从这样的信息中看不出其他游泳的信息。
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);
我们利用Reflection提供的内置方法export来打印信息,如下所示:
打印出的信息比较完整,包括成员属性,成员方法,类的基本信息,文件路径,方法信息,方法属性,传参情况,所在文件的行数等等。比较全面的展示了类的信息。可以看出var_dump()或者print_r只能显示类的简要信息,好多信息根本显示不出来,所以他们只能做简单的调试之用,反射Api则提供的类更多的信息,可以很好地帮助我们知道调用类的情况,这对写接口,特别是调用别人的接口提供了极大的便利。如果出了问题,也可以帮助调试。
<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 />.....
反射API的具体使用:
看过框架源码的同学都知道框架都可以加载第三方的插件、类库等等。下面这个例子咱们借助反射APi简单实现这个功能,该例子原型是我从书上学习的,我理解后按照自己的思路写了一套:要实现的功能:用一个类去动态的遍历调用Property类对象,类可以自由的加载其他的类的方法,而不用吧类嵌入到已有的代码,也不用手动去调用类库的代码。
约定:每一个类要包含work方法,可以抽象出一个接口。可以把每个类的信息放在文件中,相当于各个类库信息,通过类保存的Property类库的对应对象,然后调用每个类库的work方法。
下面是基础代码:
<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> }
这里定义了两个相似类实现Property接口,同时都简单实现work()方法 StudentController类稍微不同,参数需要Person对象,同时我们可以使用文件来保存各个类的信息,我们也可以用成员属性代替。
<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();
到此程序结束,Run启动会自动调用构造方法,初始化要加载类库的其他成员属性,包括初始化和执行相应方法操作,这里只是完成了对应的set方法。其中$mod_arr属性保存了所有调用类的对象,每个对象包含数据,可以遍历包含的对象来以此调用work()方法。
程序只做辅助理解反射PAI用,各个功能没有完善,里面用到了好多反射API的类,方法,下面会有各个方法的总结。
反射API提供的常用类和函数:
下面提供的函数是常用的函数,不是全部,有的函数根本用不到,所以我们有往撒谎那个写,想看全部的可以到网上搜一下,比较多。提供的这组方法没有必要背下来,用到的时候可以查看。
<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> }
写的比较急,难免会有错误,还请大神们多多指正。
转载请注明出处,谢啦!