• PHP反射


    说到反射,实际上包含两个概念:

    • 检视 introspection 判断类、方法是否存在,父子类关系,调用关系等,检视的函数文档
    • 反射 Reflection 获取类里的方法、属性,注释等,反射类的文档

    PHP官方文档写得很清晰了,下面我就说一下具体的应用。
    1.参数检测
    有时候需要在函数里需要判断传入的参数类型是否合法。
    这时可以使用is_a、is_subclass_of来检测。或者结合反射,做更多检测。
    2.动态调用
    在依赖注入中,常见到这种用法,比如Laravel5.5中的Container.php

    public function build($concrete)
        {
            // If the concrete type is actually a Closure, we will just execute it and
            // hand back the results of the functions, which allows functions to be
            // used as resolvers for more fine-tuned resolution of these objects.
            if ($concrete instanceof Closure) {
                return $concrete($this, $this->getLastParameterOverride());
            }
            $reflector = new ReflectionClass($concrete);
            // If the type is not instantiable, the developer is attempting to resolve
            // an abstract type such as an Interface of Abstract Class and there is
            // no binding registered for the abstractions so we need to bail out.
            if (! $reflector->isInstantiable()) {
                return $this->notInstantiable($concrete);
            }
            $this->buildStack[] = $concrete;
            $constructor = $reflector->getConstructor();
            // If there are no constructors, that means there are no dependencies then
            // we can just resolve the instances of the objects right away, without
            // resolving any other types or dependencies out of these containers.
            if (is_null($constructor)) {
                array_pop($this->buildStack);
                return new $concrete;
            }
            $dependencies = $constructor->getParameters();
            // Once we have all the constructor's parameters we can create each of the
            // dependency instances and then use the reflection instances to make a
            // new instance of this class, injecting the created dependencies in.
            $instances = $this->resolveDependencies(
                $dependencies
            );
            array_pop($this->buildStack);
            return $reflector->newInstanceArgs($instances);
        }
    

    上述代码先判断是否是闭包,如果是,直接返回。不是则通过new ReflectionClass($concrete);
    生成反射类的实例,然后获取这个类的构造函数和参数,进行初始化的过程。
    注意
    反射里一个比较重要的用法invoke
    当已知这个类的时候,可以通过构造ReflectionMethod来直接调用,如:

    class HelloWorld {
    
        public function sayHelloTo($name) {
            return 'Hello ' . $name;
        }
    
    }
    
    $reflectionMethod = new ReflectionMethod('HelloWorld', 'sayHelloTo');
    echo $reflectionMethod->invoke(new HelloWorld(), 'Mike');
    

    当不知道这个类时,知道类的对象,可以用ReflectionObject获取ReflectionMethod后调用,如:

    class HelloWorld {
    
        public function sayHelloTo($name) {
            return 'Hello ' . $name;
        }
    
    }
    
    $hello = new HelloWorld();
    
    $refObj = new ReflectionObject($hello);
    $refMethod = $refObj->getMethod('sayHelloTo');
    echo $refMethod->invoke($hello,'Mike');
    

    调用流程一般就是获取反射类ReflectionClass/反射对象ReflectionObject的实例,然后获取ReflectionMethod后,invoke。

    3.获取注释,生成文档
    比如PHPDoc

    4.注解,增强版的注释,符合一定的规则
    比如某些框架的路由,便是通过注解实现的。

    5.不要为了反射而反射
    PHP是一门动态语言,其实可以直接通过字符串来调用类或函数,如下:

    class HelloWorld {
    
        public function sayHelloTo($name) {
            return 'Hello ' . $name;
        }
    
    }
    
    $hello = 'HelloWorld';
    $helloSay = 'sayHelloTo';
    $helloIntance = new $hello;
    echo $helloIntance->$helloSay('Mike');
    

    那么为什么还需要反射呢?

    • 功能更强大
    • 更安全,防止直接调用没有暴露的内部方法
    • 可维护,直接写字符串是硬编码
  • 相关阅读:
    python 单体模式 的几种实现
    python 相对路径导入 与 绝对路径导入
    python 优雅地实现插件架构
    tkinter 弹出窗口 传值回到 主窗口
    flask 与 vue.js 2.0 实现 todo list
    FormData 数据转化为 json 数据
    vue.js 2.0实现的简单分页
    一个神奇的实现:计算数组尾部对称长度
    flask, SQLAlchemy, sqlite3 实现 RESTful API 的 todo list, 同时支持form操作
    SQLAlchemy 关联表删除实验
  • 原文地址:https://www.cnblogs.com/xdao/p/php_reflection.html
Copyright © 2020-2023  润新知