[PHP] - PHP 反射是什么

PHP 中的反射

PHP 反射是一种“自省”能力,也就是看到自己的意思。

通俗的来说,通过反射可以获取类中的变量、方法名称甚至是注释等等,在正常的开发环境中几乎不会用到,一般都是在框架设计时使用,目的是增加框架的扩展性。

Laravel、swoft 框架都用到了反射机制,swoft 注解的实现原理就是使用反射机制来实现的。

请结合下面的示例进行理解。

示例

我们定义了一个类,类里面有常量、私有属性(private 声明的变量)、类的注释和方法的注释等等。

来看看下面几个业务中几乎不会用到的问题:

如果我们要获取一个类里面的所有常量,应该怎么做?

如果我们要获取一个方法的注释,或者类的注释,应该怎么做?

如果我们要获得一个类的命名空间,又该怎么做?

此时习惯了做业务的我们肯定一脸懵逼,PHP 中的反射就是为了解决这一类的问题,通过反射提供的 API 可以拿到一个类的所有信息。

通过下面的代码举例,你马上就会弄懂什么是反射了!

<?php
/**
 * 类的注释
 */
class User
{
    const BOY = 1;
    const GIRL = 2;

    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    /**
     * 我是方法注释
     */
    public function sayHello() {
        echo 'hello!';
    }
}

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

var_dump($comment_method);

上面的代码会输出:

string(39) "/**
     * 我是方法注释
     */"

由于反射提供的功能在我们平时的业务基本用不到,经常用到框架的设计上。

反射 API

PHP 官方手册:https://www.php.net/reflection

应用场景

自动生成文档

由于反射可以拿到类的属性、方法,就可以自动生成类的文档。

克隆类

同理,既然可以拿到类的所有成员,那克隆出一个基于基类的子类简直易如反掌,在一些框架或插件中经常用到,比如用插件的功能克隆出 Model 文件。

<?php
/**
 * 类的注释
 */
class User
{
    const BOY = 1;
    const GIRL = 2;

    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    /**
     * 我是方法注释
     */
    public function sayHello() {
        echo 'hello!';
    }
}

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

$file = 'clone.php';

$content = '<?php' . PHP_EOL . $class->getDocComment() .  PHP_EOL . 'class ' . $class->getName() . PHP_EOL . '{'. PHP_EOL;

foreach($constants as $key => $value) {
    $content .= '    const ' . $key . ' = ' . $value . ';' . PHP_EOL . PHP_EOL;
}

$content .= PHP_EOL . '}';

// ... 此处省略其他成员

file_put_contents($file, $content);

通过该方法可以克隆出一个 User 类文件。

其他场景

由于本人接触的较少,如有兴趣请自行搜索相关运用场景。

讨论

还没有人评论~