内容简介:前几天有人在PHP的QQ群里问生成对象的问题:类似问题五六年前碰到过,因此印象深刻。热心提示要用 “
问题
前几天有人在 PHP 的QQ群里问生成对象的问题:
use A\B; $b = new B(); // 正确 $str = "B"; $b = new $str(); // 错误,提示:类"B"未找到
类似问题五六年前碰到过,因此印象深刻。热心提示要用 “ 完全限定类名 ” 形式,可惜连说两遍,提问题的人都没理解我说的(或者认为我的回复与其问题无关):
不得已下,写下示范代码并 @ 提问题的人,终于让其明白:
原理
问题解决了,背后的原理是什么?
从人的角度看,代码意图非常明显:动态生成类 B
的实例。但从执行引擎的角度,完全是另外一回事。其实 new $classname()
背后的运作行为类似于:
// 伪代码
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
。
那么PHP能否改进一下 class_exists
和 ReflectionClass
的行为,让其根据当前上下文判断?
可以这么做,但是代价很大,原因包括:
-
class_exists和ReflectionClass都没有指示程序上下文Context的参数; - PHP比较坑的一点: 类名 不会像函数、常量一样往上逐级查找;
-
如果存在多个同名的类,加载哪个?如以下代码所示:
不管采取哪种行为,都会招致吐槽。
保持目前的情况,除动态生成实例时需要完全限定类名,并无其他槽点。并且实现上简单,行为明确且一致。
总结
作为一门脚本语言,PHP非常的灵活,但也会带来一些使用上的困惑。本文所讨论的根据类名动态生成对象,就要无视当前所在或引入的名字空间,必须使用完全限定类名形式。
作为对比,C++不能动态生成对象。Java要用 Class.forName
的方式获取 class
对象,然后再调用构造函数生成。Java不能直接 new
类名,避免了PHP中的坑,但 Class.forName
同样需要完全限定类名,避免不明确行为。
参考
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Pragmatic Programmer
Andrew Hunt、David Thomas / Addison-Wesley Professional / 1999-10-30 / USD 49.99
本书直击编程陈地,穿过了软件开发中日益增长的规范和技术藩篱,对核心过程进行了审视――即根据需求,创建用户乐于接受的、可工作和易维护的代码。本书包含的内容从个人责任到职业发展,直至保持代码灵活和易于改编重用的架构技术。从本书中将学到防止软件变质、消除复制知识的陷阱、编写灵活、动态和易适应的代码、避免出现相同的设计、用契约、断言和异常对代码进行防护等内容。一起来看看 《The Pragmatic Programmer》 这本书的介绍吧!
在线进制转换器
各进制数互转换器
HSV CMYK 转换工具
HSV CMYK互换工具