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() . "\n";
}
// 输出:
// _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] . "\n";
 }
}
// 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('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 关键字。否则找不到类名会抛出异常。
一旦创建了反射类的实例,我们不仅可以通过反射类访问原来类的方法和属性,还能创建原来类的实例或则直接调用类里面的方法。

posted @ 2019-02-20 23:58  绝技小嗨皮  阅读(148)  评论(0编辑  收藏  举报
Title