如何使用反射来分析PHP的数据结构

Go qloog · 2018年06月02日 · 1607 次阅读


更准备的说是 如何用PHP分析类内部的结构。

介绍

当我开始学习PHP编程时,可能并不知道 Reflection API 的强大功能,主要原因是我不需要它来设计我的类,模块甚至是包等等,但是它在很多地方都有非常不错的能力。

下面我们来介绍 Reflection API,主要是从这几个方面

  1. 什么是Reflection API?
  2. 安装和配置
  3. 使用
  4. 总结

什么是 Reflection API

Reflection 是计算机程序在运行时检查,修改自己的结构和行为的能力 - 维基百科

这是什么意思呢?让我们来看下面的代码片段:

/**
 * Class Profile
 */
class Profile
{
   /**
    * @return string
    */
   public function getUserName(): string
   {
      return 'Foo';
   }
}

现在,Profile类是一个使用 ReflectionClass 的黑盒子,你可以获取它里面的内容:

// instantiation
$reflectionClass = new ReflectionClass('Profile');

// get class name
var_dump($reflectionClass->getName());
=> output: string(7) "Profile"

// get class documentation
var_dump($reflectionClass->getDocComment());
=> output:
string(24) "/**
 * Class Profile
 */"

因此,ReflectionClass 就像我们Profile类的分析师,这是 Reflection API 的主要思想。

除了上面用到的,其实还有更多,如下:

ReflectionClass:报告一个类的信息。
ReflectionFunction:报告有关函数的信息。
ReflectionParameter:检索有关函数或方法参数的信息。
ReflectionClassConstant:报告关于类常量的信息。

更多文档可以看这里 反射

安装和配置

Reflection API 是PHP内置的,不需要安装或配置,它已经是PHP核心的一部分。

使用

在这里,我们通过更多,来看如何使用 Reflection API:

例一:获取特定类的父类

// here we have the child class
class Child extends Profile
{
}

$class = new ReflectionClass('Child');

// here we get the list of all parents
print_r($class->getParentClass()); // ['Profile']

例二:获取 getUserName() 函数注释

$method = new ReflectionMethod('Profile', 'getUserName');
var_dump($method->getDocComment());
=> output:
string(33) "/**
 * @return string
 */"

例三:它可以像 instanceofis_a() 一样来验证对象:

$class = new ReflectionClass('Profile');
$obj   = new Profile();

var_dump($class->isInstance($obj)); // bool(true)

// same like
var_dump(is_a($obj, 'Profile')); // bool(true)

// same like
var_dump($obj instanceof Profile); // bool(true)

例子四:在某些情况下,你会发现自己停留在单元测试中,想知道如何测试私有函数?!

// add getName() scope as private
private function getName(): string
{
    return 'Foo';
}

$method = new ReflectionMethod('Profile', 'getUserName');
// check if it is private so we set it as accessible
if ($method->isPrivate()) {
    $method->setAccessible(true);
}

echo $method->invoke(new Profile()); // Foo

前面的例子非常简单,下面是一些可以广泛查找Reflection API的地方:

  • 文档生成器:laravel-apidoc-generator软件包,它广泛使用ReflectionClassReflectionMethod 来获取关于类和方法的信息,然后处理它们,检出这个代码块。

  • 依赖注入容器:下一篇来看。

结论

PHP提供了一个丰富的反射API,使我们可以更容易到达OOP结构的任何区域。

说白了就是在PHP运行时,可以通过反射深入到类的内部,做我们想做的事情。

欢迎留言讨论 ^_^