PHP 反射类及用法

2015-05-28 22:29:24   最后更新: 2015-05-28 23:19:06   访问数量:2468




面向对象编程中,对象被赋予了自省的能力,也就是通过类对象找到类对象的来源,这个自省的过程就被称为“反射”

作为面向对象语言的后起之秀,PHP 拥有更加强大的反射机制

 

对于一个类,我们怎么获取其方法和属性列表呢?

以下函数可以完成此功能:

 

获取 PHP 类对象属性和方法的函数
函数功能
get_class(obj)获取对象 obj 所对应的类名
get_object_vars(obj)获取对象 obj 具有的类属性(返回关联数组)
get_class_vars(cls)获取类名 cls 的类属性(返回关联数组)
get_class_methods(cls)获取类名 cls 具有的类方法(返回关联数组)

 

然而,反射 API 功能显然更加强大

 

 

<?php class ReflectionClass implements Reflector { /* 常量 */ const integer IS_IMPLICIT_ABSTRACT = 16 ; const integer IS_EXPLICIT_ABSTRACT = 32 ; const integer IS_FINAL = 64 ; /* 属性 */ public $name ; /* 方法 */ public __construct ( mixed $argument ); public static string export ( mixed $argument [, bool $return = false ] ); public mixed getConstant ( string $name ); public array getConstants ( void ); public ReflectionMethod getConstructor ( void ); public array getDefaultProperties ( void ); public string getDocComment ( void ); public int getEndLine ( void ); public ReflectionExtension getExtension ( void ); public string getExtensionName ( void ); public string getFileName ( void ); public array getInterfaceNames ( void ); public array getInterfaces ( void ); public ReflectionMethod getMethod ( string $name ); public array getMethods ([ int $filter ] ); public int getModifiers ( void ); public string getName ( void ); public string getNamespaceName ( void ); public object getParentClass ( void ); public array getProperties ([ int $filter ] ); public ReflectionProperty getProperty ( string $name ); public string getShortName ( void ); public int getStartLine ( void ); public array getStaticProperties ( void ); public mixed getStaticPropertyValue ( string $name [, mixed &$def_value ] ); public array getTraitAliases ( void ); public array getTraitNames ( void ); public array getTraits ( void ); public bool hasConstant ( string $name ); public bool hasMethod ( string $name ); public bool hasProperty ( string $name ); public bool implementsInterface ( string $interface ); public bool inNamespace ( void ); public bool isAbstract ( void ); public bool isCloneable ( void ); public bool isFinal ( void ); public bool isInstance ( object $object ); public bool isInstantiable ( void ); public bool isInterface ( void ); public bool isInternal ( void ); public bool isIterateable ( void ); public bool isSubclassOf ( string $class ); public bool isTrait ( void ); public bool isUserDefined ( void ); public object newInstance ( mixed $args [, mixed $... ] ); public object newInstanceArgs ([ array $args ] ); public object newInstanceWithoutConstructor ( void ); public void setStaticPropertyValue ( string $name , string $value ); public string __toString ( void ); } ?>

 

 

既可以使用一个包含类名的字符串(string)也可以使用一个类对象(object)来构造 ReflectionObject 类

 

ReflectionObject 类成员函数列表
函数功能
ReflectionClass::__construct构造一个 ReflectionClass 类
ReflectionClass::export导出一个类(static 函数)
ReflectionClass::getConstant获取定义过的一个常量
ReflectionClass::getConstants获取一组常量
ReflectionClass::getConstructor获取类的构造函数
ReflectionClass::getDefaultProperties获取默认属性
ReflectionClass::getDocComment获取文档注释
ReflectionClass::getEndLine获取最后一行的行数
ReflectionClass::getExtension根据已定义的类获取所在扩展的 ReflectionExtension 对象
ReflectionClass::getExtensionName获取定义的类所在的扩展的名称
ReflectionClass::getFileName获取定义类的文件名
ReflectionClass::getInterfaceNames获取接口(interface)名称
ReflectionClass::getInterfaces获取接口
ReflectionClass::getMethod获取一个类方法的 ReflectionMethod。
ReflectionClass::getMethods获取方法的数组
ReflectionClass::getModifiers获取修饰符
ReflectionClass::getName获取类名
ReflectionClass::getNamespaceName获取命名空间的名称
ReflectionClass::getParentClass获取父类
ReflectionClass::getProperties获取一组属性
ReflectionClass::getProperty获取类的一个属性的 ReflectionProperty
ReflectionClass::getShortName获取短名
ReflectionClass::getStartLine获取起始行号
ReflectionClass::getStaticProperties获取静态(static)属性
ReflectionClass::getStaticPropertyValue获取静态(static)属性的值
ReflectionClass::getTraitAliases返回 trait 别名的一个数组
ReflectionClass::getTraitNames返回这个类所使用 traits 的名称的数组
ReflectionClass::getTraits返回这个类所使用的 traits 数组
ReflectionClass::hasConstant检查常量是否已经定义
ReflectionClass::hasMethod检查方法是否已定义
ReflectionClass::hasProperty检查属性是否已定义
ReflectionClass::implementsInterface接口的实现
ReflectionClass::inNamespace检查是否位于命名空间中
ReflectionClass::isAbstract检查类是否是抽象类(abstract)
ReflectionClass::isCloneable返回了一个类是否可复制
ReflectionClass::isFinal检查类是否声明为 final
ReflectionClass::isInstance检查类的实例
ReflectionClass::isInstantiable检查类是否可实例化
ReflectionClass::isInterface检查类是否是一个接口(interface)
ReflectionClass::isInternal检查类是否由扩展或核心在内部定义
ReflectionClass::isIterateable检查是否可迭代(iterateable)
ReflectionClass::isSubclassOf检查是否为一个子类
ReflectionClass::isTrait返回了是否为一个 trait
ReflectionClass::isUserDefined检查是否由用户定义的
ReflectionClass::newInstance从指定的参数创建一个新的类实例
ReflectionClass::newInstanceArgs从给出的参数创建一个新的类实例。
ReflectionClass::newInstanceWithoutConstructor创建一个新的类实例而不调用它的构造函数
ReflectionClass::setStaticPropertyValue设置静态属性的值
ReflectionClass::__toString返回 ReflectionClass 对象字符串的表示形式

 

PHP 反射类的功能是非常强大的,十分有必要深入研究和使用

主要有以下功能:

  1. 文档生成:可以通过对文件中的类进行扫描,逐个生成描述文档
  2. 动态代理:由于反射可以探知类的内部结构,因此可以用它做 hook 实现插件功能和动态代理,使程序极其灵活
  3. 调试:在调试中,获取类的信息也是常常用到的功能

 

注意

由于反射的灵活性,善用反射可以有效的保持代码的通用性,是代码更加简洁和优雅

但是相反的,反射也会破坏类的封装性,强制暴露出了类的方法和属性,堪称是一把双刃剑

同时,由于反射机制的消耗很大,在有替代方案的情况下不应滥用反射

 

下面的代码举出了一个使用反射的例子,在 MVC 和插件开发中,反射也经常被使用

<?php class Mysql { function connect($db) { echo "连接到数据库 ${ db[0] }\r\n"; } } class SqlProxy { private $target; function __construct($tar) { $this->target[] = new $tar(); } function __call($name, $args) { foreach ($this->target as $obj) { $r = new ReflectionObject($obj); if ($method = $r->getMethod) { if ($method->isPublic() && !$method->isAbstract()) { echo "方法拦截\r\n"; $method->invoke($obj, $args); } } } } } $obj = new SqlProxy('Mysql'); $obj->connect('database'); ?>

 

 

上面的例子中,SqlProxy 实现了对 sql 的代理访问和拦截,而实际创建的类对象时 Mysql 类型的

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 






技术帖      php      mvc      框架      技术分享            反射      面向对象      面向对象编程      oop      oo      对象      framework     


1#keygle: (回复)2017-04-24 21:48:30

例子的代码有问题 应该是 <?php class Mysql { function connect($db) { echo "连接到数据库 ${ db[0] }\r\n"; } } class SqlProxy { private $target; function __construct($tar) { $this->target[] = new $tar(); } function __call($name, $args) { foreach ($this->target as $obj) { $r = new ReflectionObject($obj); if ($method = $r->getMethod($name)) { if ($method->isPublic() && !$method->isAbstract()) { echo "方法拦截\r\n"; $method->invoke($obj, $args); } } } } } $obj = new SqlProxy('Mysql'); $obj->connect('database');

2#keygle: (回复)2017-04-24 21:49:43

上面的格式乱了 应该是 $method = $r->getMethod 这一行 应该为 $method = $r->getMethod($name)

京ICP备15018585号