• PHP反射机制


    简介

    • PHP自5.0版本以后添加了反射机制,它提供了一套强大的反射API,允许你在PHP运行环境中,访问和使用类、方法、属性、参数和注释等,其功能十分强大,经常用于高扩展的PHP框架,自动加载插件,自动生成文档,甚至可以用来扩展PHP语言。

    • PHP反射api由若干类组成,可帮助我们用来访问程序的元数据或者同相关的注释交互。借助反射我们可以获取诸如类实现了那些方法,创建一个类的实例(不同于用new创建),调用一个方法(也不同于常规调用),传递参数,动态调用类的静态方法。

    • 反射api是PHP内建的OOP技术扩展,为语言本身自带的特性,不需要额外添加扩展或者配置就可以使用;包括一些类,异常和接口,综合使用他们可用来帮助我们分析其它类,接口,方法,属性,方法和扩展。这些OOP扩展被称为反射。

    反射类型

    PHP反射API会基于类,方法,属性,参数等维护相应的反射类,已提供相应的调用API。

    类型 说明
    Reflector Reflector 是一个接口,被所有可导出的反射类所实现(implement)
    Reflection 反射(reflection)类
    ReflectionClass 报告了一个类的有关信息
    ReflectionZendExtension 报告Zend扩展的相关信息
    ReflectionExtension 报告了PHP扩展的有关信息
    ReflectionFunction 报告了一个函数的有关信息
    ReflectionFunctionAbstract ReflectionFunction 的父类
    ReflectionMethod 报告了一个方法的有关信息
    ReflectionObject 报告了一个对象(object)的相关信息
    ReflectionParameter 取回了函数或方法参数的相关信息
    ReflectionProperty 报告了类的属性的相关信息

    示例

    
    <?php
    class Person {
    
     /**
      * For the sake of demonstration, we"re setting this private
      */
     private $_allowDynamicAttributes = false;
    
     /**
      * type=primary_autoincrement
      */
     protected $id = 0;
    
     /**
      * type=varchar length=255 null
      */
     protected $name;
    
     /**
      * type=text null
      */
     protected $biography;
    
     public function getId() {
      return $this->id;
     }
    
     public function setId($v) {
      $this->id = $v;
     }
    
     public function getName() {
      return $this->name;
     }
    
     public function setName($v) {
      $this->name = $v;
     }
    
     public function getBiography() {
      return $this->biography;
     }
    
     public function setBiography($v) {
      $this->biography = $v;
     }
    }
    
    

    ReflectionClass类

    通过ReflectionClass,我们可以得到Person类的以下信息:

    1.常量 Contants
    2.属性 Property Names
    3.方法 Method Names静态
    4.属性 Static Properties
    5.命名空间 Namespace
    6.Person类是否为final或者abstract
    7.Person类是否有某个方法

    接下来反射它,只要把类名"Person"传递给ReflectionClass就可以了:

    
    $class = new ReflectionClass('Person'); // 建立 Person这个类的反射类  
    $instance  = $class->newInstanceArgs($args); // 相当于实例化Person 类 
    
    
    • 获取属性
    $properties = $class->getProperties();
    foreach ($properties as $property) {
     echo $property->getName() . "
    ";
    }
    // 输出:
    // _allowDynamicAttributes
    // id
    // name
    // biography
    
    

    默认情况下,ReflectionClass会获取到所有的属性,private 和 protected的也可以。如果只想获取到private属性,就要额外传个参数:

    
    $private_properties = $class->getProperties(ReflectionProperty::IS_PRIVATE);
    

    可用参数列表:

    ReflectionProperty::IS_STATIC
    ReflectionProperty::IS_PUBLIC
    ReflectionProperty::IS_PROTECTED
    ReflectionProperty::IS_PRIVATE
    
    • 获取注释
      通过getDocComment可以得到写给property的注释:
    foreach ($properties as $property) {
     if ($property->isProtected()) {
      $docblock = $property->getDocComment();
      preg_match('/ type=([a-z_]*) /', $property->getDocComment(), $matches);
      echo $matches[1] . "
    ";
     }
    }
    // Output:
    // primary_autoincrement
    // varchar
    // text
    
    • 获取类的方法
    getMethods()       来获取到类的所有methods。
    hasMethod(string)  是否存在某个方法
    getMethod(string)  获取方法
    
    
    • 执行类的方法
    $instance->getName(); // 执行Person 里的方法getName
    // 或者:
    $method = $class->getmethod('getName'); // 获取Person 类中的getName方法
    $method->invoke($instance);    // 执行getName 方法
    // 或者:
    $method = $class->getmethod('setName'); // 获取Person 类中的setName方法
    $method->invokeArgs($instance, array('snsgou.com'));
    

    ReflectionMethod类

    通过ReflectionMethod,我们可以得到Person类的某个方法的信息:

    1.是否“public”、“protected”、“private” 、“static”类型
    2.方法的参数列表
    3.方法的参数个数
    4.反调用类的方法

    // 执行detail方法
    $method = new ReflectionMethod('Person', 'test');
     
    
    if ($method->isPublic() && !$method->isStatic()) {
     echo 'Action is right';
    }
    echo $method->getNumberOfParameters(); // 参数个数
    echo $method->getParameters(); // 参数对象数组
    

    补充

    $class = new ReflectionClass('ExtendUser'); // 将类名User作为参数,即可建立User类的反射类
    $properties = $class->getProperties(); // 获取User类的所有属性,返回ReflectionProperty的数组
    $property = $class->getProperty('password'); // 获取User类的password属性ReflectionProperty
    $methods = $class->getMethods(); // 获取User类的所有方法,返回ReflectionMethod数组
    $method = $class->getMethod('getUsername'); // 获取User类的getUsername方法的ReflectionMethod
    $constants = $class->getConstants(); // 获取所有常量,返回常量定义数组
    $constant = $class->getConstant('ROLE'); // 获取ROLE常量
    $namespace = $class->getNamespaceName(); // 获取类的命名空间
    $comment_class = $class->getDocComment(); // 获取User类的注释文档,即定义在类之前的注释
    $comment_method = $class->getMethod('getUsername')->getDocComment(); // 获取User类中getUsername方法的注释文档

    注意:
    创建反射类时传送的类名,必须包含完整的命名空间,即使使用了 use 关键字。否则找不到类名会抛出异常。
    一旦创建了反射类的实例,我们不仅可以通过反射类访问原来类的方法和属性,还能创建原来类的实例或则直接调用类里面的方法。

    正因为来之不易,所以才有了后来的倍加珍惜。
  • 相关阅读:
    Linux基础巩固--Day4--文本处理
    Linux基础巩固--Day3--用户组及权限操作
    2020撸python--argparse列出D盘目录详情
    2020撸python--socket编程
    Linux基础巩固--Day2--文件操作
    Linux基础巩固--Day1--背景介绍
    Let's Go -- 初始go语言
    ValueError: Related model 'users.UserProfile' cannot be resolved
    半虚拟化驱动virtio-Windows
    virt-install 创建虚拟机
  • 原文地址:https://www.cnblogs.com/jjxhp/p/10409933.html
Copyright © 2020-2023  润新知