圣泉山人 后端开发工程师

PHP反射

2017-04-05
PHP

什么是反射

反射是指在PHP运行状态中,扩展分析PHP程序,导出或提出关于类、方法、属性、参数等的详细信息,包括注释。这种动态获取信息以及动态调用对象方法的功能称为反射。

简单的理解:反射机制就是可以利用类名或者一个类的对象来获取关于这个类的一系列信息(类的变量,方法),然后又就可以利用得到的类的信息实例化一些类的对象

一般在框架中使用到反射机制比较多(控制反转)。

PHP提供的反射API

  • Reflection
  • ReflectionClass
  • ReflectionClassConstant
  • ReflectionZendExtension
  • ReflectionExtension
  • eflectionFunction
  • ReflectionFunctionAbstract
  • ReflectionMethod
  • ReflectionObject
  • ReflectionParameter
  • ReflectionProperty
  • ReflectionType
  • ReflectionGenerator
  • Reflector 接口
  • ReflectionException

具体可以参考手册:http://php.net/manual/zh/book.reflection.php

使用

常用:

  • ReflectionClass :通过类名反射
  • ReflectionObject : 通过对象反射

获取类的原型

比如有个如下类:

class Student {

    /**
     * @var string name of student .
     */
    private $name;

    /**
     * @var int age of student
     */
    private $age;

    public function getName():string
    {
        return $this->name;
    }

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

    public function getAge():int
    {
        return $this->name;
    }

    public function setAge(int $age)
    {
        $this->age = $age;
    }

    public function printInfo():string
    {
        echo $this->name . ':' . $this->age;
    }
}

可以通过反射API来获取类或者对象的一些信息:

$student = new Student();
$student->setName('Jack');
$student->setAge(24);


//通过类名反射:使用 ReflectionClass
$student = new ReflectionClass(Student::class);
$properties = $student->getProperties();
foreach ($properties as $property) {
    //注释,但是格式要符合要求
    var_export($property->getDocComment());
    //属性名
    var_export($property->getName());
    //权限
    var_dump($property->isPublic() . $property->isPrivate());
}

//通过类的具体对象来进行反射:使用 ReflectionObject
$studentObj = new ReflectionObject($student);
$properties = $studentObj->getProperties();
$methodes = $studentObj->getMethods();
foreach ($methodes as $method) {
    //输出所有的方法名
    print $method->getName() . PHP_EOL;
}

//不通过反射API,使用class函数:
//返回由对象属性组成的关联数组
var_dump(get_object_vars($student));
//返回类属性
var_dump(get_class_vars(Student::class));
// 返回由类的方法名组成的数组
var_dump(get_class_methods(get_class($student)));

动态代理

class Mysql {
    public function connect($params)
    {
        echo "connect mysql..."  , json_encode($params),PHP_EOL;
    }
}

class Oracle {
    public function connect($params)
    {
        echo "connect oracle..." , json_encode($params), PHP_EOL;
    }
}

class DbProxy {
    private $target = [];

    /**
     * DbProxy constructor.
     * @param $name 类名
     * @throws Exception
     */
    public function __construct($name)
    {
        if (!class_exists($name)) {
            throw new Exception('Class: '.$name.' not found');
        }
        $this->target[] = new $name();
    }

    /**
     * @param $methodName 方法名字
     * @param array ...$params 参数列表
     * @throws Exception
     * @return mixed
     */
    public function call($methodName, ...$params)
    {
        foreach ($this->target as $targetObj) {
            $reflect = new ReflectionObject($targetObj);
            if ($method = $reflect->getMethod($methodName)) {
                if ($method->isPublic()) {
                    echo 'begin exec', PHP_EOL;
                    $res = $method->invoke($targetObj, $params);
                    echo 'end exec', PHP_EOL;
                    return $res;
                } else {
                    throw new Exception('Method: '.$methodName.' is not public');
                }
            } else {
                throw new Exception('Method: '.$methodName.' not found');
            }
        }
    }
}

//使用代理执行指定方法
$mysqlProxy = new DbProxy(Mysql::class);
$res = $mysqlProxy->call('connect');
$res = $mysqlProxy->call('connect', ['host' => 'localhost']);

$oracleProxy = new DbProxy(Oracle::class);
$res = $oracleProxy->call('connect');
var_dump($res);

Similar Posts

上一篇 PHP SAPI

Comments