PHP反射API

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

近期忙着写项目,没有学习什么特别新的东西,所以好长时间没有更新博客。我们的项目用的是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的区别

下面是一段我自己写的参数程序,用于演示反射的使用:

1<?php23classPerson4{5//成员属性6public$name;7public$age;89//构造方法10publicfunction__construct($name,$age)11{12$this->name =$name;13$this->age =$age;14}1516//成员方法17publicfunctionset_name($name)18{19$this->$name=$name;20}2122publicfunctionget_name()23{24return$this->$name;25}2627publicfunctionget_age()28{29return$this->$age;30}3132publicfunctionget_user_info()33{34$info= '姓名:' .$this->name;35$info.= ' 年龄:' .$this->age;36return$info;37}38}3940classTeacherextendsPerson41{42PRivate$salary= 0;4344publicfunction__construct($name,$age,$salary)45{46parent::__construct($name,$age);47$this->salary =$salary;48}4950publicfunctionget_salary()51{52return$this->$salary;53}5455publicfunctionget_user_info()56{57$info= parent::get_user_info();58$info.= " 工资:" .$this->salary;59return$info;60}61}6263classStudentextendsPerson64{65private$score= 0;6667publicfunction__construct($name,$age,$score)68{69parent::__construct($name,$age);70$this->score =$score;71}7273publicfunctionget_score()74{75return$this->score;76}7778publicfunctionget_user_info()79{80$info= parent::get_user_info();81$info.= " 成绩:" .$this->score;82return$info;83}84}8586header("Content-type:text/html;charset=utf8;");87$te_obj=newTeacher('李老师', '36', '2000');88$te_info=$te_obj->get_user_info();8990$st_obj=newStudent('小明', '13', '80');91$st_info=$st_obj->get_user_info();

我们先用var_dump();打印类的信息,如下所示,可以看出只是打印出类的简单信息,甚至连方法也没有,所以从这样的信息中看不出其他游泳的信息。

var_dump($te_obj);

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

Reflection::export($obj);

我们利用Reflection提供的内置方法export来打印信息,如下所示:

打印出的信息比较完整,包括成员属性,成员方法,类的基本信息,文件路径,方法信息,方法属性,传参情况,所在文件的行数等等。比较全面的展示了类的信息。可以看出var_dump()或者print_r只能显示类的简要信息,好多信息根本显示不出来,所以他们只能做简单的调试之用,反射Api则提供的类更多的信息,可以很好地帮助我们知道调用类的情况,这对写接口,特别是调用别人的接口提供了极大的便利。如果出了问题,也可以帮助调试。

1object(Teacher)#1 (3) {2["salary":"Teacher":private]=>3string(4) "2000"4["name"]=>5string(9) "李老师"6["age"]=>7string(2) "36"8}9Class[classPerson ] {10@@ /usr/local/www/phptest/oop/reflaction.php 3-3811- Constants [0] {12}13-Staticproperties [0] {14}15-Staticmethods [0] {16}17- Properties [2] {18Property [public$name]19Property [public$age]20}2122- Methods [5] {23Method [publicmethod __construct ] {24@@ /usr/local/www/phptest/oop/reflaction.php 10 - 142526- Parameters [2] {27Parameter#0 [ $name ]

.....

反射API的具体使用:

看过框架源码的同学都知道框架都可以加载第三方的插件、类库等等。下面这个例子咱们借助反射APi简单实现这个功能,该例子原型是我从书上学习的,我理解后按照自己的思路写了一套:要实现的功能:用一个类去动态的遍历调用Property类对象,类可以自由的加载其他的类的方法,而不用吧类嵌入到已有的代码,也不用手动去调用类库的代码。

约定:每一个类要包含work方法,可以抽象出一个接口。可以把每个类的信息放在文件中,相当于各个类库信息,通过类保存的Property类库的对应对象,然后调用每个类库的work方法。

下面是基础代码:

1/*属性接口*/2interfaceProperty3{4functionwork();5}67classPerson8{9public$name;10publicfunction__construct($name)11{12$this->name =$name;13}14}1516classStudentControllerimplementsProperty17{18//set方法,但需要Person对象参数19publicfunctionsetPerson(Person$obj_person)20{21echo'Student ' .$obj_person->name;22}2324//work方法简单实现25publicfunctionwork()26{27echo'student working!';28}29}3031classEngineControllerimplementsProperty32{33//set方法34publicfunctionsetWeight($weight)35{36echo'this is engine -> set weight';37}3839publicfunctionsetPrice($price)40{41echo"this is engine -> set price";42}4344//work方法简单实现45publicfunctionwork()46{47echo'engine working!';48}49}

这里定义了两个相似类实现Property接口,同时都简单实现work()方法 StudentController类稍微不同,参数需要Person对象,同时我们可以使用文件来保存各个类的信息,我们也可以用成员属性代替。

1classRun2{3publicstatic$mod_arr=[];4publicstatic$config=[5'StudentController' =>[6'person' => 'xiao ming'7],8'EngineController' =>[9'weight' => '500kg',10'price' => '4000'11]12];1314//加载初始化15publicfunction__construct()16{17$config= self::$config;18//用于检查是不是实现类19$property=newReflectionClass('Property');20foreach($configas$class_name=>$params) {21$class_reflect=newReflectionClass($class_name);22if(!$class_reflect->isSubclassOf($property)) {//用isSubclassOf方法检查是否是这个对象23echo'this is error';24continue;25}2627//得到类的信息28$class_obj=$class_reflect->newInstance();29$class_method=$class_reflect->getMethods();3031foreach($class_methodas$method_name) {32$this->handle_method($class_obj,$method_name,$params);33}34array_push(self::$mod_arr,$class_obj);35}36}3738//处理方法调用39publicfunctionhandle_method(Property$class_obj, ReflectionMethod$method_name,$params)40{41$m_name=$method_name->getName();42$args=$method_name->getParameters();4344if(count($args) != 1 ||substr($m_name, 0, 3) != 'set') {45returnfalse;46}47//大小写转换,做容错处理48$property=strtolower(substr($m_name, 3));4950if(!isset($params[$property])) {51returnfalse;52}5354$args_class=$args[0]->getClass();55echo'<pre>';56if(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}6364//程序开始65newRun();

到此程序结束,Run启动会自动调用构造方法,初始化要加载类库的其他成员属性,包括初始化和执行相应方法操作,这里只是完成了对应的set方法。其中$mod_arr属性保存了所有调用类的对象,每个对象包含数据,可以遍历包含的对象来以此调用work()方法。

程序只做辅助理解反射PAI用,各个功能没有完善,里面用到了好多反射API的类,方法,下面会有各个方法的总结。

反射API提供的常用类和函数:

下面提供的函数是常用的函数,不是全部,有的函数根本用不到,所以我们有往撒谎那个写,想看全部的可以到网上搜一下,比较多。提供的这组方法没有必要背下来,用到的时候可以查看。

11:Reflection2publicstaticexport(Reflector r [,boolreturn])//打印类或方法的详细信息3publicstaticgetModifierNames(int modifiers)//取得修饰符的名字452:ReflectionMethod:6publicstaticstringexport()//打印该方法的信息7publicmixedinvoke(stdclassobject,mixed* args)//调用对应的方法8publicmixedinvokeArgs(stdclassobject,arrayargs)//调用对应的方法,传多参数9publicbool isFinal()//方法是否为final10publicbool isAbstract()//方法是否为abstract11publicbool isPublic() //方法是否为public12publicbool isPrivate() //方法是否为private13publicbool isProtected() //方法是否为protected14publicbool isStatic() //方法是否为static15publicbool isConstructor() //方法是否为构造函数17183:ReflectionClass:19publicstaticstringexport()//打印类的详细信息20publicstringgetName()//取得类名或接口名21publicbool isInternal() //类是否为系统内部类22publicbool isUserDefined() //类是否为用户自定义类23publicbool isInstantiable()//类是否被实例化过24publicbool hasMethod(stringname)//类是否有特定的方法25publicbool hasproperty(stringname)//类是否有特定的属性26publicstringgetFileName()//获取定义该类的文件名,包括路径名27publicint getStartLine()//获取定义该类的开始行28publicint getEndLine()//获取定义该类的结束行29publicstringgetDocComment()//获取该类的注释30publicReflectionMethod getConstructor() //取得该类的构造函数信息31publicReflectionMethod getMethod(stringname) //取得该类的某个特定的方法信息32publicReflectionMethod[] getMethods() //取得该类的所有的方法信息33publicReflectionProperty getProperty(stringname)//取得某个特定的属性信息34publicReflectionProperty[] getProperties()//取得该类的所有属性信息35publicarraygetConstants()//取得该类所有常量信息36publicmixedgetConstant(stringname)//取得该类特定常量信息37publicReflectionClass[] getInterfaces()//取得接口类信息38publicbool isInterface()//测试该类是否为接口39publicbool isAbstract()//测试该类是否为抽象类40414:ReflectionParameter:42publicstaticstringexport() //导出该参数的详细信息43publicstringgetName() //取得参数名44publicbool isPassedByReference()//测试该参数是否通过引用传递参数45publicReflectionClass getClass()//若该参数为对象,返回该对象的类名46publicbool isArray() //测试该参数是否为数组类型47publicbool allowsNull() //测试该参数是否允许为空48publicbool isOptional()//测试该参数是否为可选的,当有默认参数时可选49publicbool isDefaultValueAvailable()//测试该参数是否为默认参数50publicmixedgetDefaultValue()//取得该参数的默认值51525:ReflectionExtension类54publicstaticexport()//导出该扩展的所有信息55publicstringgetName()//取得该扩展的名字56publicstringgetVersion()//取得该扩展的版本57publicReflectionFunction[] getFunctions()//取得该扩展的所有函数58publicarraygetConstants()//取得该扩展的所有常量59publicarraygetINIEntries()//取得与该扩展相关的,在php.ini中的指令信息60}

写的比较急,难免会有错误,还请大神们多多指正。

转载请注明出处,谢啦!

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航