27 07 2020

常用的反射类


类名作用
Reflection可以打印类的基本信息,(通过提供的静态export()函数)
ReflectionMethod见名知意,打印类方法、得到方法的具体信息等
ReflectionClass用于得到类信息,比如得到类包含的方法,类本的属性,是不是抽象类等
ReflectionParameter显示参数的信息,可以动态得到已知方法的传参情况
ReflectionException用于显示错误信息
ReflectionExtension得到PHP的扩展信息,可以判断扩展是否存在等


extend/A.php

<?php

/**
 * Class A
 */
class A
{
    public $a;
    private $b;

    public function __construct($a, $b)
    {
        $this->a = $a;
        $this->b = $b;
    }

    /**
     * A类的abc方法
     *
     * @param $a
     * @param $b
     *
     * @return string
     */
    public function abc($a, $b)
    {
        return "abcd";
    }

    /**
     * type方法
     *
     * @param int $type
     *
     * @return string
     */
    public function type($type = 1)
    {
        return "type:" . $type;
    }
}


application/index/controller/Index.php

反射类和获取属性

//$obj = new \A("a", 'b');
//$refClass = new \ReflectionClass($obj);
//或者
$refClass = new \ReflectionClass("A"); // 将类名作为参数,建立反射类

//var_dump($refClass);
/**
 * 打印
 * object(ReflectionClass)#34 (1)
 * {
 *      ["name"]=> string(1) "A"
 * }
 */


$properties = $refClass->getProperties(); // 所有属性

//var_dump($properties);
/**
 * 打印
 * array(2)
 * {
 *  [0]=> object(ReflectionProperty)#35 (2)
 *      {
 *          ["name"]=> string(1) "a"
 *          ["class"]=> string(1) "A"
 *      }
 *  [1]=> object(ReflectionProperty)#36 (2)
 *      {
 *          ["name"]=> string(1) "b"
 *          ["class"]=> string(1) "A"
 *      }
 * }
 */

$property = $refClass->getProperty('a');
//var_dump($property);
/**
 * 打印
 * object(ReflectionProperty)#37 (2)
 * {
 *      ["name"]=> string(1) "a"
 *      ["class"]=> string(1) "A"
 * }
 */


反射方法

$methods = $refClass->getMethods(); // 获取类的所有方法
//var_dump($methods);
/**
 * 打印
 * array(3)
 * {
 *  [0]=> object(ReflectionMethod)#38 (2)
 *  {
 *      ["name"]=> string(11) "__construct"
 *      ["class"]=> string(1) "A"
 *  }
 *  [1]=> object(ReflectionMethod)#39 (2)
 *  {
 *      ["name"]=> string(3) "abc"
 *      ["class"]=> string(1) "A"
 *  }
 *  [2]=> object(ReflectionMethod)#40 (2)
 *  {
 *      ["name"]=> string(2) "mf"
 *      ["class"]=> string(1) "A"
 *  }
 * }
 */

$method = $refClass->getMethod("abc");
//var_dump($method);
/**
 * 打印
 * object(ReflectionMethod)#41 (2)
 * {
 *      ["name"]=> string(3) "abc"
 *      ["class"]=> string(1) "A"
 * }
 */


反射注释

$document = $refClass->getDocComment(); // 获取类定义在类之前的注释
//var_dump($document);

// 打印
// string(18) "/** * Class A */"

$document = $refClass->getMethod('abc')->getDocComment();
//var_dump($document);

// 打印
// string(105) "/** * A类的abc方法 * * @param $a * @param $b * * @return string */"


反射实例化新类

$newInstance = $refClass->newInstance("a", "b");  // 从指定的参数创建一个新的类实例
//var_dump($newInstance);
/**
 * 打印
 * object(A)#42 (2)
 * {
 *      ["a"]=> string(1) "a"
 *      ["b":"A":private]=> string(1) "b"
 * }
 */
$params = ['a', "b"];
$newInstance = $refClass->newInstanceArgs($params); // 从给出的参数创建一个新的类实例
//var_dump($newInstance);
/**
 * 打印
 * object(A)#42 (2)
 * {
 *      ["a"]=> string(1) "a"
 *      ["b":"A":private]=> string(1) "b"
 * }
 */


反射实例化新类可访问、执行类的公有方法

$ret = $newInstance->type(1); // 调用类的实例调用type方法
//var_dump($ret);
// 打印
// string(6) "type:1"

$refClass->getProperty('a')->setValue($newInstance, 'a'); // 设置属性值
$a = $refClass->getProperty('a')->getValue($newInstance);   // 获取属性值
//var_dump($a);
// 打印
// string(1) "a"

$ret = $refClass->getMethod('type')->invoke($newInstance, '2'); // 调用类的实例调用type方法
//var_dump($ret);
// 打印
// string(6) "type:2"


判断某个方法是否公用的

$method = new \ReflectionMethod('A', 'abc');
var_dump($method->isPublic());
// 打印
// bool(true)


THINKPHP 源码中的使用

thinkphp/library/think/Container.php

class Container implements ArrayAccess, IteratorAggregate, Countable
{
  ......
  
    /**
     * 调用反射执行类的方法 支持参数绑定
     * @access public
     * @param  mixed   $method 方法
     * @param  array   $vars   参数
     * @return mixed
     */
    public function invokeMethod($method, $vars = [])
    {
        try {
            if (is_array($method)) {
                $class   = is_object($method[0]) ? $method[0] : $this->invokeClass($method[0]);
                $reflect = new ReflectionMethod($class, $method[1]);
            } else {
                // 静态方法
                $reflect = new ReflectionMethod($method);
            }
    
            $args = $this->bindParams($reflect, $vars);
    
            return $reflect->invokeArgs(isset($class) ? $class : null, $args);
        } catch (ReflectionException $e) {
            if (is_array($method) && is_object($method[0])) {
                $method[0] = get_class($method[0]);
            }
    
            throw new Exception('method not exists: ' . (is_array($method) ? $method[0] . '::' . $method[1] : $method) . '()');
        }
    }
    
    ......
    
    /**
     * 调用反射执行类的实例化 支持依赖注入
     * @access public
     * @param  string    $class 类名
     * @param  array     $vars  参数
     * @return mixed
     */
    public function invokeClass($class, $vars = [])
    {
        try {
            $reflect = new ReflectionClass($class);
    
            if ($reflect->hasMethod('__make')) {
                $method = new ReflectionMethod($class, '__make');
    
                if ($method->isPublic() && $method->isStatic()) {
                    $args = $this->bindParams($method, $vars);
                    return $method->invokeArgs(null, $args);
                }
            }
    
            $constructor = $reflect->getConstructor();
    
            $args = $constructor ? $this->bindParams($constructor, $vars) : [];
    
            return $reflect->newInstanceArgs($args);
    
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException('class not exists: ' . $class, $class);
        }
    }
    
    ......
}