PHP 反射

PHP对反射提供了完整的支持。http://php.net/manual/zh/intro.reflection.php

类图简单结构:

命令行工具:

php —help
  --rf <name>      Show information about function <name>.
  --rc <name>      Show information about class <name>.
  --re <name>      Show information about extension <name>.
  --rz <name>      Show information about Zend extension <name>.
  --ri <name>      Show configuration for extension <name>.

查看一个实例:

class B {
    public function test()
    {
        echo date("Y-m-d H:i:s") . "\n";
    }
}

class A {
    public $b = null;

    public $try = 0;

    public function __construct(B $b, $try = 111)
    {
        $this->b = $b;
        $this->try = $try;
    }

    public function test()
    {
        echo "B-------\n";
        $this->b->test();
        echo "A--------\n";
        echo date("Y-m-d H:i:s") . "\n";
        var_dump($this->try);
        echo "\n";
    }
}

// 反射类
$reflector = new ReflectionClass(A::class);
// 是否可实例化
$instantiable = $reflector->isInstantiable();
if ($instantiable) {
    // 取到构造函数
    $constructor = $reflector->getConstructor();
    // 取到构造函数的参数
    $dependencies = $constructor->getParameters();
    print_r($constructor);
    print_r($dependencies);
    $instances = [];
    // 根据构造函数的参数,确定依赖
    foreach ($dependencies as $idx => $dependency) {
        // $dependency是一个ReflectionParameter对象实例
        // getClass()取回参数对应的类原型定义(如果不是类则返回null)
        $class = $dependency->getClass();
        if (is_null($class)) {
           echo $dependency->getName() . " - Class is Null \n";
           // 确定参数是否可选,如果可选则使用默认值
           if ($dependency->isOptional()) {
               $instances[$idx] = $dependency->getDefaultValue();
           } else {
               throw new Exception();
           }
        } else {
            echo $dependency->getName() . " - Class is $class->name \n";
            try {
                // 构建对象
                $className = $class->name;
                $instances[$idx] = new $className();
            } catch (Exception $e) {
                if ($dependency->isOptional()) {
                    $instances[$idx] = $dependency->getDefaultValue();
                }
                throw $e;
            }
        }
    }
    // 把取回的依赖注入构造函数
    $a = $reflector->newInstanceArgs($instances);
    $a->test();
}

这个实例中,A类的构造函数需要注入B类对象。利用反射的支持,先取回A类的构造函数,然后分析构造函数参数,根据参数自动实例化依赖,最后生成对象。这里有一个问题,如果B类实例化时需要依赖其它类对象注入该怎么办? 实际这个就是一个递归过程而已。如果需要构建一个对象,对象的依赖自动解决(依赖对象自动生成),这个只有利用反射能实现。

反射也是实现依赖注入容器的基础。