PHP反射机制

简介

就算是类成员定义为private也能够在外部访问,不用建立类的实例也能够访问类的成员和方法。php

PHP自5.0版本之后添加了反射机制,它提供了一套强大的反射API,容许你在PHP运行环境中,访问和使用类、方法、属性、参数和注释等,其功能十分强大,常常用于高扩展的PHP框架,自动加载插件,自动生成文档,甚至能够用来扩展PHP语言。因为它是PHP內建的oop扩展,为语言自己自带的特性,因此不须要额外添加扩展或者配置就可使用。更多内容见官方文档数组

反射类型

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

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

访问

假设定义了一个类 User,咱们首先须要创建这个类的反射类实例,而后基于这个实例能够访问 User 中的属性或者方法。无论类中定义的成员权限声明是否为public,均可以获取到。函数

<?php 
namespace Extend;

use ReflectionClass;
use Exception;

/**
 * 用户相关类
 * Class User
 * @package Extend
 */
class User{
    const ROLE = 'Students';
    public $username = '';
    private $password = '';

    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
    }

    /**
     * 获取用户名
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * 设置用户名
     * @param string $username
     */
    public function setUsername($username)
    {
        $this->username = $username;
    }

    /**
     * 获取密码
     * @return string
     */
    private function getPassword()
    {
        return $this->password;
    }

    /**
     * 设置密码
     * @param string $password
     */
    private function setPassowrd($password)
    {
        $this->password = $password;
    }
}

$class = new ReflectionClass('Extend\User');  // 将类名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 关键字。不然找不到类名会抛出异常。oop

交互

一旦建立了反射类的实例,咱们不只能够经过反射类访问原来类的方法和属性,还能建立原来类的实例或则直接调用类里面的方法。this

$class = new ReflectionClass('Extend\User');  // 将类名User做为参数,便可创建User类的反射类
$instance = $class->newInstance('youyou', 1, '***');  // 建立User类的实例

$instance->setUsername('youyou_2');  // 调用User类的实例调用setUsername方法设置用户名
$value = $instance->getUsername();   // 用过User类的实例调用getUsername方法获取用户名
echo $value;echo "\n";   // 输出 youyou_2

$class->getProperty('username')->setValue($instance, 'youyou_3');  // 经过反射类ReflectionProperty设置指定实例的username属性值
$value = $class->getProperty('username')->getValue($instance);  // 经过反射类ReflectionProperty获取username的属性值
echo $value;echo "\n";   // 输出 youyou_3

$class->getMethod('setUsername')->invoke($instance, 'youyou_4'); // 经过反射类ReflectionMethod调用指定实例的方法,而且传送参数
$value = $class->getMethod('getUsername')->invoke($instance);    // 经过反射类ReflectionMethod调用指定实例的方法
echo $value;echo "\n";   // 输出 youyou_4

try {
    $property = $class->getProperty('password_1');
    $property->setAccessible(true);   // 修改 $property 对象的可访问性
    $property->setValue($instance, 'password_2');  // 能够执行
    $value = $property->getValue($instance);     // 能够执行
    echo $value;echo "\n";   // 输出 password_2
    $class->getProperty('password')->setAccessible(true);    // 修改临时ReflectionProperty对象的可访问性
    $class->getProperty('password')->setValue($instance, 'password');// 不能执行,抛出不能访问异常
    $value = $class->getProperty('password')->getValue($instance);   // 不能执行,抛出不能访问异常
    $value = $instance->password;   // 不能执行,类自己的属性没有被修改,仍然是private
}catch(Exception $e){echo $e;}

注意事项

  1. 直接访问 protected 或则 private 的熟悉或者方法会抛出异常
  2. 须要调用指定的 ReflectionProperty 或则 ReflectionMethod 对象 setAccessible(true)方法才能访问非公有成员
  3. 修改非公有成员的访问权限只做用于当前的反射类的实例
  4. 须要注意获取静态成员和非静态成员所使用的方法不同
  5. 获取父类成员的方法和通常的不同

有时间会整理出反射类的API表,详细的API列表能够先查阅官方文档spa

相关文章
相关标签/搜索