zoukankan      html  css  js  c++  java
  • 【反射】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和插件开发中,使用反射很常见,但是反射的消耗也很大,在可以找到替代方案的情况下,不要滥用反射。

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


  • 相关阅读:
    [LeetCode]Sort List
    [LeetCode]Single Number II
    合并两个排序的列表
    翻转链表
    链表中倒数第k个结点
    调整数组顺序使奇数位于偶数前面
    数值的整数次方
    二进制中1的个数
    矩形覆盖
    变态跳台阶
  • 原文地址:https://www.cnblogs.com/linewman/p/9918116.html
Copyright © 2011-2022 走看看