【反射】PHP的反射机制【原创】

摘要:主要是参考列旭松、陈文著的《PHP核心技术与最佳实践》的1.5节。

1.1 定义

反射,直观理解就是根据到达地找到出发地和来源。比如说,给你一个光秃秃的对象,可以仅仅通过这个对象就能知道它所属的类以及拥有的方法。
反射,指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。这种动态获取信息以及动态调用对象方法的功能称为反射API。

1.2 获取对象属性和方法

getMethods和 getProperties分别用来获取对象的所有方法和所有属性,返回对象数组,然后通过getName来获取具体的方法和属性即可。但都是必须先通过 反射获取类的原型, 即使用 $reflect = new ReflectionObject($student);来获取对象的原型。
下面是使用反射API来获取对象的属性和方法:
运行:
Setting age to 24
Tom is male

对象的属性有:
name
gender
age
Array
(
    [0] => ReflectionProperty Object
        (
            [name] => name
            [class] => Person3
        )

    [1] => ReflectionProperty Object
        (
            [name] => gender
            [class] => Person3
        )

    [2] => ReflectionProperty Object
        (
            [name] => age
            [class] => Person3
        )

)

对象的方法有:
say
__set
__get
Array
(
    [0] => ReflectionMethod Object
        (
            [name] => say
            [class] => Person3
        )

    [1] => ReflectionMethod Object
        (
            [name] => __set
            [class] => Person3
        )

    [2] => ReflectionMethod Object
        (
            [name] => __get
            [class] => Person3
        )

)
------------------分隔线-----------------
对象属性的关联数组:
Array
(
    [name] => Tom
    [gender] => male
    [age] => 24
)
对象属性列表所属的类:
Person3类属性:
Array
(
    [name] =>
    [gender] =>
)
类的方法名组成的数组:
Array
(
    [0] => say
    [1] => __set
    [2] => __get
)



1.3 还原类的原型

既然上面已经可以使用反射来获取对象的属性和方法了,那么再进一步,获取方法和属性的访问权限,那么就可以根据对象来获取类的原型了:
PHP手册中关于反射API的有很多,可以说,反射完整的描述了一个类或者对象的原型。反射不仅可以用于类和对象,还可以用于函数、扩展模块、异常等。

1.4 反射的invoke方法

invoke方法是个很实用的方法,用来执行一个反射的方法:
<?php
/**
 * 使用反射API的invoke方法来执行反射的方法
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/7/13
 * Time: 18:23
 */

class HelloWorld
{
    public function sayHelloTo($name) {
        return 'Hello ' . $name;
    }

}

// 获取反射的方法
$method = new ReflectionMethod('HelloWorld', 'sayHelloTo');
/** 上面的代码和下面注释的代码作用是一样的   */
//$reflectionClass = new ReflectionClass('HelloWorld');
//$method = $reflectionClass->getMethod('sayHelloTo');

// 执行一个反射的方法
echo $method->invoke(new HelloWorld(), 'Mike');    // Hello Mike


其中的:
作用相当于:
$reflectionClass = new ReflectionClass('HelloWorld');
$method = $reflectionClass->getMethod('sayHelloTo');



1.5 动态代理

使用反射的invoke方法,可以实现简单的动态代理:
运行:
方法前拦截记录 Log
已经连接到数据库member
方法后拦截
方法前拦截记录 Log
已经连接到数据库lottery
方法后拦截

这里简单说明一下,真正的操作类是MySql类,但 SqlProxy类实现了根据动态传入参数,代替实际的类MySql类的运行,并且在方法运行前后进行拦截,并且可以动态改变类中的方法和属性,这就是简单的动态代理。

1.6 反射的作用

反射的用处:
  • 用于文档生成,因此可以用它对文件里的类进行扫描,逐个生成描述文档。
  • 用来做hook实现插件功能
  • 动态代理

在平常开发中,用到反射的地方很有限,主要有两个地方,一个是对对象进行调试,另一个是获取类的信息。而在MVC和插件开发中,使用反射很常见,但是反射的消耗也很大,在可以找到替代方案的情况下,不要滥用反射。

很多时候,善用反射能够保持代码的优雅和简洁,但反射也会破坏类的封装性,因为反射可以使本不应该暴露的方法或者属性被强制暴露了出来,这既是优点也是缺点。


发布了64 篇原创文章 · 获赞 47 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/jiandanokok/article/details/75136985