PHP反射API (转)

http://www.cnblogs.com/zyf-zhaoyafei/p/4922893.html

近期忙着写项目,没有学习什么特别新的东西,所以好长时间没有更新博客。我们的项目用的是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 <?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来打印信息,如下所示:

  打印出的信息比较完整,包括成员属性,成员方法,类的基本信息,文件路径,方法信息,方法属性,传参情况,所在文件的行数等等。比较全面的展示了类的信息。可以看出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 }

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

时间: 2024-10-26 00:10:44

PHP反射API (转)的相关文章

反射API

class HelloWorld{ public function sayHelloTo($name,$value){ return 'Hello,'.$name.$value; }}$reflectionMethod=new ReflectionMethod('HelloWorld', 'sayHelloTo');echo $reflectionMethod->invokeArgs(new HelloWorld(), array('kcc','fuck','back')); 反射API,布布扣

反射——反射API,使用反射创建数组

反射API Java.lang.Reflect库 ①   Class类与Java.lang.Reflect类库一起对反射的概念进行支持. ②   java.lang包下: a)         Class<T>:表示对一个正在运行的Java应用程序中的类和接口,是Reflection的起源. ③   java.lang.reflect包下: a)         Field类:代表类的成员变量(成员变量也称类的属性). b)         Method类:代表类的方法. c)        

Atitit.跨语言反射api&#160;兼容性提升与增强&#160;java&#160;c#。Net&#160;&#160;php&#160;&#160;js

Atitit.跨语言反射api 兼容性提升与增强 java c#.Net  php  js 1. 什么是反射1 1.1.       反射提供的主要功能:2 1.2.       实现反射的过程:2 2. 类反射中所必须的类: 的类反射所需要的类并不多,它们分别是:Field.Constructor.Method.Class.Object,2 3. . 反射的用处3 3.1. 可视化 3 3.2. 系统的灵活性.可扩展性 3 3.3. Json xml序列化3 3.4. 函数指针3 3.5. R

Swift反射API及其用法

猛戳查看最终版@SwiftGG 尽管 Swift 一直在强调强类型.编译时安全和静态调度,但它的标准库仍然提供了反射机制.可能你已经在很多博客文章或者类似Tuples.Midi Packets 和 Core Data 的项目中见过它.也许你刚好对在项目中使用反射机制感兴趣,或者你想更好滴了解反射可以应用的领域,那这篇文章就正是你需要的.文章的内容是基于我在德国法兰克福 Macoun会议上的一次演讲,它对 Swift 的反射 API 做了一个概述. API 概述 理解这个主题最好的方式就是看API

JDK1.7新特性(4):java语言动态性之反射API

直接通过一个代码示例来熟悉java中通过反射来对构造函数/域以及方法处理的相关API: 1 package com.rampage.jdk7.chapter2; 2 3 import java.lang.reflect.Array; 4 import java.lang.reflect.Constructor; 5 import java.lang.reflect.Field; 6 import java.lang.reflect.InvocationTargetException; 7 imp

利用反射api查找一个类的详细信息

说到这个实例,首先介绍下本人,我是一个php程序员,从事drupal开发2年多,可以说从实习开始就接触这个,至今没有换过,drupal给我的感觉是俩字"强大",今天写一个views的字段,然后需要继承views的views_handler_field类,还要自己实现里面的一些方法,走一些自己的配置设置,查看这个类的时候,发现实在是太多信息了,并且做了好些继承,于是我就想要是能实现一个功能,传入一个类名,然后就能返回类的所有信息(包括,属性,方法,继承,接口,并且这些类所放置的文件位置,

详解PHP反射API

原文:详解PHP反射API PHP中的反射API就像Java中的java.lang.reflect包一样.它由一系列可以分析属性.方法和类的内置类组成.它在某些方面和对象函数相似,比如get_class_vars(),但是更加灵活,而且可以提供更多信息.反射API也可与PHP最新的面向对象特性一起工作,如访问控制.接口和抽象类.旧的类函数则不太容易与这些新特性一起使用.看过框架源码的朋友应该对PHP的反射机制有一定的了解,像是依赖注入,对象池,类加载,一些设计模式等等,都用到了反射机制. 1.

PHP反射API

<?php /** * @name PHP反射API--利用反射技术实现的插件系统架构 */ /** * 先调用findPlugins方法获取到获取到实现了接口的类 * 然后调用反射类的方法 * @param $method 方法名 * @param $interfaceName 接口名 * @return array 方法名对应的返回结果 */ function compute($method,$interfaceName){ $findPlugins = findPlugins($inter

Java反射API研究(2)——java.lang.reflect详细内容与关系

对于最新的java1.8而言,reflect中接口的结构是这样的: java.lang.reflect.AnnotatedElement java.lang.reflect.AnnotatedType java.lang.reflect.AnnotatedArrayType java.lang.reflect.AnnotatedParameterizedType java.lang.reflect.AnnotatedTypeVariable java.lang.reflect.Annotated