Fork me on GitHub

PHP进阶基础知识剖析(二)之反射API

烈火试真金,逆境试强者。
塞内加

前言

既写了魔术方法之后,接下来再来剖析另外一个很有趣的东西--------反射API,这个语法在很多OOPL中都存在,PHP中自然也少不了。接下来我们就进入他的世界!!

那么本期要讲述的是关于反射API的知识

介绍

反射,顾名思义,直观理解就是根据到达地找到出发地和来源。通俗点说,就是给你一个光秃秃的对象,我们可以通过它知道他所属的类、以及属性、方法、参数甚至注释等一切。。。。。


这是一种动态获取信息以及动态调用对象方法的功能

主要作用

  • 用于自动生成类的定义文档
  • 当需要去实例化一个类,但是这个类完全就是封闭或者说是未知的,你可以创建反射来与映射这个类,通过一系列的探测来最终实例化这个类,尤其还在动态运行中的。
  • 可以做动态代理和做hook实现插件功能
  • 可用于调试和单元测试

详解具体API

首先,反射API的实现是从一个接口实现开始,这个接口叫做Reflector,接口定义如下:

1
2
3
4
5
interface Reflector {
/* 方法 */
public static string export ( void )
public string __toString ( void )
}

其他的基础反射类都是基于此接口实现。请看下图列出了几种常见的反射类:

图1

我们以ReflectionClass类来说明,对于这个类其中提供了很多的方法,下面展示的是官方给出的其中的方法。


ReflectionClass::__construct — 初始化 ReflectionClass 类


ReflectionClass::export — 导出一个类


ReflectionClass::getConstant — 获取定义过的一个常量
ReflectionClass::getConstants — 获取一组常量
ReflectionClass::getConstructor — 获取类的构造函数
ReflectionClass::getDefaultProperties — 获取默认属性
ReflectionClass::getDocComment — 获取文档注释
ReflectionClass::getEndLine — 获取最后一行的行数
ReflectionClass::getExtension — 根据已定义的类获取所在扩展的 ReflectionExtension 对象
ReflectionClass::getExtensionName — 获取定义的类所在的扩展的名称
ReflectionClass::getFileName — 获取定义类的文件名
ReflectionClass::getInterfaceNames — 获取接口(interface)名称
ReflectionClass::getInterfaces — 获取接口
ReflectionClass::getMethod — 获取一个类方法的 ReflectionMethod。
ReflectionClass::getMethods — 获取方法的数组
ReflectionClass::getModifiers — 获取类的修饰符
ReflectionClass::getName — 获取类名
ReflectionClass::getNamespaceName — 获取命名空间的名称
ReflectionClass::getParentClass — 获取父类
ReflectionClass::getProperties — 获取一组属性
ReflectionClass::getProperty — 获取类的一个属性的 ReflectionProperty
ReflectionClass::getReflectionConstant — Gets a ReflectionClassConstant for a class’s constant
ReflectionClass::getReflectionConstants — Gets class constants
ReflectionClass::getShortName — 获取短名
ReflectionClass::getStartLine — 获取起始行号
ReflectionClass::getStaticProperties — 获取静态(static)属性
ReflectionClass::getStaticPropertyValue — 获取静态(static)属性的值
ReflectionClass::getTraitAliases — 返回 trait 别名的一个数组
ReflectionClass::getTraitNames — 返回这个类所使用 traits 的名称的数组
ReflectionClass::getTraits — 返回这个类所使用的 traits 数组


ReflectionClass::hasConstant — 检查常量是否已经定义
ReflectionClass::hasMethod — 检查方法是否已定义
ReflectionClass::hasProperty — 检查属性是否已定义
ReflectionClass::implementsInterface — 接口的实现
ReflectionClass::inNamespace — 检查是否位于命名空间中
ReflectionClass::isAbstract — 检查类是否是抽象类(abstract)
ReflectionClass::isAnonymous — 检查类是否是匿名类
ReflectionClass::isCloneable — 返回了一个类是否可复制
ReflectionClass::isFinal — 检查类是否声明为 final
ReflectionClass::isInstance — 检查类的实例
ReflectionClass::isInstantiable — 检查类是否可实例化
ReflectionClass::isInterface — 检查类是否是一个接口(interface)
ReflectionClass::isInternal — 检查类是否由扩展或核心在内部定义
ReflectionClass::isIterateable — 检查是否可迭代(iterateable)
ReflectionClass::isSubclassOf — 检查是否为一个子类
ReflectionClass::isTrait — 返回了是否为一个 trait
ReflectionClass::isUserDefined — 检查是否由用户定义的


ReflectionClass::newInstance — 从指定的参数创建一个新的类实例
ReflectionClass::newInstanceArgs — 从给出的参数创建一个新的类实例。
ReflectionClass::newInstanceWithoutConstructor — 创建一个新的类实例而不调用它的构造函数
ReflectionClass::setStaticPropertyValue — 设置静态属性的值
ReflectionClass::__toString — 返回 ReflectionClass 对象字符串的表示形式。

那么方法众多,我们也无法一一讲解,大体分为几类:构造函数、打印类信息(export)、获取类信息(getxxx方法)、检查类、创建新类等

对于获取类信息的方法,PHP本身内置了许多诸如get_class_methods、get_class、get_called_class等方法用来快速获取类及方法、属性等信息,但完全没有反射API强大

示例

接下来,我来展示一个反射API使用示例,很多框架中也是如此实现Ioc容器的,可以说反射还是很好用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Container
{
protected static $classMap = array();
protected static $container;

/**
* @return Container
* 单例模式获取全局唯一的容器对象
*/
public static function getSingleton()
{
if (self::$container === null) {
self::$container = new self();
}
return self::$container;
}

/**
* @param $componentName
* @param array $params
* @return mixed
* @throws \ReflectionException
* 经典的Ioc容器获取对应类
*/
public static function getClass($componentName,$params = [])
{
if (!isset(self::$classMap[$componentName])) {
$ref = new \ReflectionClass($componentName);
self::$classMap[$componentName] = $ref->newInstanceArgs($params);//给构造函数以数组形式传参
}
return self::$classMap[$componentName];
}
}

分析:

很多经典的框架结构动态实现都是运用了反射API,他们在不用知道具体类如何实现的前提下,根据需要的服务类名,通过反射机制,生成对应的服务对象加入服务容器中,供框架使用。

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!
0%