转载请注明文章出处:tlanyan.me/dynamic-new…php
前几天有人在PHP的QQ群里问生成对象的问题:函数
use A\B;
$b = new B(); // 正确
$str = "B";
$b = new $str(); // 错误,提示:类"B"未找到
复制代码
相似问题五六年前碰到过,所以印象深入。热心提示要用 "彻底限定类名" 形式,惋惜连说两遍,提问题的人都没理解我说的(或者认为个人回复与其问题无关):spa
不得已下,写下示范代码并 @ 提问题的人,终于让其明白:.net
问题解决了,背后的原理是什么?code
从人的角度看,代码意图很是明显:动态生成类B
的实例。但从执行引擎的角度,彻底是另一回事。其实new $classname()
背后的运做行为相似于:cdn
// 伪代码
if (class_exists($str)) {
$b = new $str();
return $b;
}
throw ClassNotFoundException;
// 或者用反射
try {
$reflectionClass = new ReflectionClass($str);
$b = $reflectionClass.newInstance();
return $b;
}
throw ClassNotFoundException;
复制代码
要根据类名动态生成示例,首先要判断类是否存在吧?PHP中与之相关的是class_exists
函数和ReflectionClass
类。在上面的例子中,只传入字符串 "B",class_exists
回返回true
吗?对象
答案是否认的。class_exists
和ReflectionClass
只会在全局类列表中根据名字查找,不会理会调用函数所在(或引入)的名字空间。同理,若是使用use
引入类名并作别名(as
),别名类在class_exists
中也会返回false
。blog
那么PHP可否改进一下class_exists
和ReflectionClass
的行为,让其根据当前上下文判断?字符串
能够这么作,可是代价很大,缘由包括:get
class_exists
和ReflectionClass
都没有指示程序上下文Context
的参数;
PHP比较坑的一点:类名不会像函数、常量同样往上逐级查找;
若是存在多个同名的类,加载哪一个?如如下代码所示:
无论采起哪一种行为,都会招致吐槽。
保持目前的状况,除动态生成实例时须要彻底限定类名,并没有其余槽点。而且实现上简单,行为明确且一致。
做为一门脚本语言,PHP很是的灵活,但也会带来一些使用上的困惑。本文所讨论的根据类名动态生成对象,就要无视当前所在或引入的名字空间,必须使用彻底限定类名形式。
做为对比,C++不能动态生成对象。Java要用Class.forName
的方式获取class
对象,而后再调用构造函数生成。Java不能直接new
类名,避免了PHP中的坑,但Class.forName
一样须要彻底限定类名,避免不明确行为。