$instance1 = Foo::getSingleton(); var_dump($instance1); $class = new ReflectionClass("Foo"); $constructor = $class->getConstructor(); if ((ReflectionProperty::IS_PUBLIC & $constructor->getModifiers()) === 0) { $constructor->setAccessible(true); } $instance2 = $class->newInstanceWithoutConstructor(); $constructor->invoke($instance2); var_dump($instance2); # 脚本执行结果 construct, instance id: 1 object(Foo)#1 (0) { } construct, instance id: 2 object(Foo)#4 (0) { }
我们成功的生成了两个实例,并调用构造函数完成对象初始化。如果没有反射API,这几乎是不可能完成的工作。
除了这三种操作,反射API几乎已无在运行时动态改变代码的行为。但作为动态语言,PHP内置了将数据转换成代码执行的能力(例如create_function/eval、动态函数名调用)。而PHP的好基友JavaScript则可以随时在运行时改变任意函数的行为:
PHP作为最好的语言,理应能做到在运行时动态增减/改变函数定义。这就需要用到另一个PHP核心开发者“Dmitry Zenovich”打造的大杀器:runkit拓展。这部分内容不属于反射,加之本人了解不深,不再详述。
对比
整理一下反射API和函数式API在功能上的差异:
功能
函数式API
反射API
函数是否存在
function_exists
ReflectionFunction
类是否存在
class_exits
ReflectionClass
方法是否存在
method_exits
ReflectionMethod
变量/属性是否存在
property_exits
ReflectionProperty
获取类变量
get_class_vars
ReflectionClass::getProperties
获取类方法
get_class_methods
ReflectionClass::getMethods
获取类常量
—
ReflectionClass::RegetReflectionConstant(s)
获取函数/方法参数信息
—
ReflectionFunction/Method::getParameters
获取函数/方法返回值
—
ReflectionFunction/Method::getReturnType
类使用的特性
class_uses
ReflectionClass::getTraits
获取父类
class_parents
ReflectionClass::getParentClass
获取类实现的接口
class_implements
ReflectionClass::getInterfaceNames
获取类所在名字空间
__NAMESPACE__
ReflectionClass::getNamespaceName
函数调用
call_user_func(_array)
ReflectionMethod(Function)::invoke(Args)
获取类名
__CLASS__/::class
ReflectionClass::getName
获取函数名
__METHOD__/__FUNCTION__
ReflectionFunction/Method::getName
获取类/常量/变量/方法修饰符
—
ReflectionClass/Constant/Property/Method::getModifiers
获取所在文件
__FILE__
ReflectionClass/Constant/Function/Method::getFileName
获取所在行(范围)
—
ReflectionClass/Function/Method::getStartLine/getEndLine
获取文档
—
ReflectionClass/Function/Method::getDocComment
extension_loaded
ReflectionZendExtension
拓展
get_loaded_extensions
ReflectionExtension
get_extension_funcs
从上表可以看出反射API较函数式API能提供更全面的信息。还需要注意到__FILE__这类魔术常量是编译期的工作,不是运行时的能力。
同时给出RTTI的函数式API和反射API在功能上的差异: