美文网首页我爱编程
PHP反射机制介绍

PHP反射机制介绍

作者: 祐吢房_2c9a | 来源:发表于2018-05-25 18:08 被阅读0次

    Php Reflection API是PHP5才有的新功能,它是用来导出或提取关于类、方法、属性、参数等的详细信息,包括注释。

    常用的就只有两个,ReflectionClass和ReflectionObject,前者针对类,后者针对对象,后者是继承前者的类;然后其中又有一些属性或方法能返回对应的reflection对象。

    PHP反射机制,对类、接口、函数、方法和扩展进行反向工程的能力。

    分析类、接口、函数和方法的内部结构,方法和函数的参数,以及类的属性和方法。

    常用的几个类:

    • ReflectionClass解析类
    • ReflectionProperty类的属性的相关信息
    • ReflectionMethod类方法的有关信息
    • ReflectionParameter取回函数或方法参数的相关信息
    • ReflectionFunction 一个函数的相关信息

    示例类

    class Student
    {
        public $id;
        
        public $name;
    
        const MAX_AGE = 200;
    
        public static $likes = [];
    
        public function __construct($id, $name = 'li')
        {
            $this->id = $id;
            $this->name = $name;
        }
    
        public function study()
        {
            echo 'learning...';
        }
    
        private function _foo()
        {
            echo 'foo';
        }
    
        protected function bar($to, $from = 'zh')
        {
            echo 'bar';
        }
    }
    

    ReflectionClass

    //ReflectionClass
    $ref = new ReflectionClass('student');
    
    //判断类是否可实例化
    if($ref->isInstantiable()){
        echo "可实例化";
    }
    
    //获取构造函数,有返回ReflectionMethod对象,没有返回null
    $constructor = $ref->getConstructor();
    
    //获取某个属性
    if ($ref->hasProperty('id')) {
        $attr = $ref->getProperty('id');
    }
    
    //获取属性列表
    $attributes = $ref->getProperties();
    foreach ($attributes as $row){
        echo $row->getName()."\n";
    }
    
    //获取静态属性,返回数组
    $static = $ref->getStaticProperties();
    
    //获取某个常量
    if ($ref->hasConstant('MAX_AGE')) {
        $const = $ref->getConstant('MAX_AGE');
    }
    
    //获取所有常量
    $constants = $ref->getConstants();
    
    //获取某个方法
    if ($ref->hasMethod('bar')) {
        $method = $ref->getMethod('bar');
    }
    
    //获取方法列表
    $methods = $ref->getMethods();
    

    ReflectionProperty

    if ($ref->hasProperty('name')) {
      $attr = $ref->getProperty('name');
      //属性名称
      echo $attr->getName();
      //类定义时属性为真,运行时添加的属性为假
      var_dump($attr->isDefault());
      //判断属性访问权限
      $attr->isPrivate();
      $attr->isPublic();
      $attr->isProtected();
      //判断属性是否为静态
      $attr->isStatic();
    }
    

    ReflectionMethod & ReflectionParameter

    $method = $ref->getMethod('bar');
    //对方法的判断
    //isAbstruct()
    //isConstructor()
    //isDestructor()
    //isFinal()
    //isPrivate()
    //isPublic()
    //isProtected()
    //isStatic()
    
    //获取参数列表
    $parameters = $method->getParameters();
    foreach ($parameters as $row) {
        echo $row->getName();
        echo $row->getClass();
        
        //检查是否有默认值
        if ($row->isDefaultValueAvailable()) {
            echo $row->getDefaultValue();
        }
      
        //获取变量类型
        if ($row->hasType()) {
            echo $row->getType();
        }
    }
    

    ReflectionFunction & ReflectionParameter

    $fun = new ReflectionFunction('demo');
    echo $fun->getName();
    $parameters = $fun->getParameters();
    foreach ($parameters as $row) {
        // 这里的 $row 为 ReflectionParameter 实例
        echo $row->getName();
        echo $row->getClass();
    
        // 检查变量是否有默认值
        if ($row->isDefaultValueAvailable()) {
            echo $row->getDefaultValue();
        }
    
        // 获取变量类型
        if ($row->hasType()) {
            echo $row->getType();
        }
    }
    

    综合实例

    使用反射实例化类

    //student.php
    class Student
    {
        public $id;
        
        public $name;
    
        public function __construct($id, $name)
        {
            $this->id = $id;
            $this->name = $name;
        }
    
        public function study()
        {
            echo 'learning.....';
        }
    
    }
    

    一般情况下,实例化类的时候可以直接new,但是我们现在不用这种方法,我们使用反射来实现。

    //index.php
    require 'student.php';
    function make($class, $vars = [])
    {
        $ref = new ReflectionClass($class);
      
        if ($ref->isInstantiable()) {
            $constructor = $ref->getConstructor();
            if (is_null($constructor)) {
                return new $class;
            }
          
            //获取构造函数参数
            $params = $constructor->getParameters();
            $resolveParams = [];
            foreach ($params as $key => $param) {
                $name = $param->getName();
                if (isset($vars[$name])) {
                    //判断如果是传递的参数,直接使用传递参数
                    $resolveParams[] = $vars[$name];
                } else {
                    //没有传递参数的话,检查是否有默认值,没有默认值的话,按照类名进行递归解析
                    $default = $param->isDefaultValueAvailable() ? $param->isDefaultValueAvailable() : null;
                    if (is_null($default)) {
                        if ($param->getClass()) {
                            $resolveParams[] = make($value->getClass()->name, $vars);
                        } else {
                            throw new Exception("{$name}没有传值且没有默认值");
                        }
                    } else {
                         $resolveParams[] = $default;
                    }
                }
            }
            //根据参数实例化
            return $ref->newInstanceArgs($resolveParams);
        } else {
            throw new Exception("类 {$class} 不存在");
        }
    }
    

    情况一

    try {
        $stu = make('Student', ['id' => 1, 'name'=>'li']);
        print_r($stu);
        $stu->study();
    } catch(Exception $e) {
        echo $e->getMessage();
    }
    

    情况二

    try {
        $stu = make('Student', ['id' => 1, 'name'=>'li', 'study'=> new Study]);
        print_r($stu);
        $stu->study();
    } catch(Exception $e) {
        echo $e->getMessage();
    }
    

    那么这种情况下,在分析类的构造函数参数的时候,如果没有传递参数的话,就会递归调用 make 方法处理 Study 类,如果类存在的话,实例化。
    PHP 的反射是一个很用的功能,我这里只能很简单的讲解了一点皮毛,详细介绍和用法可参看 官方手册

    相关文章

      网友评论

        本文标题:PHP反射机制介绍

        本文链接:https://www.haomeiwen.com/subject/llmujftx.html