通过类名动态生成对象

栏目: PHP · 发布时间: 6年前

内容简介:前几天有人在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_existsReflectionClass 只会在全局类列表中根据名字查找,不会理会调用函数所在(或引入)的名字空间。同理,如果使用 use 引入类名并做别名( as ),别名类在 class_exists 中也会返回 false

那么PHP能否改进一下 class_existsReflectionClass 的行为,让其根据当前上下文判断?

可以这么做,但是代价很大,原因包括:

  1. class_existsReflectionClass 都没有指示程序上下文 Context 的参数;
  2. PHP比较坑的一点: 类名 不会像函数、常量一样往上逐级查找;
  3. 如果存在多个同名的类,加载哪个?如以下代码所示:

    通过类名动态生成对象

    不管采取哪种行为,都会招致吐槽。

保持目前的情况,除动态生成实例时需要完全限定类名,并无其他槽点。并且实现上简单,行为明确且一致。

总结

作为一门脚本语言,PHP非常的灵活,但也会带来一些使用上的困惑。本文所讨论的根据类名动态生成对象,就要无视当前所在或引入的名字空间,必须使用完全限定类名形式。

作为对比,C++不能动态生成对象。Java要用 Class.forName 的方式获取 class 对象,然后再调用构造函数生成。Java不能直接 new 类名,避免了PHP中的坑,但 Class.forName 同样需要完全限定类名,避免不明确行为。

参考

  1. PHP回顾之反射
  2. PHP中的重载
  3. Using namespaces: fallback to global function/constant

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Charlotte's Web

Charlotte's Web

E. B. White / Scholastic / 2004 / USD 0.01

This is the tale of how a little girl named Ferm, with the help of a friendly spider, saved her pig, Wilbur, from the usual fate of nice fat little pigs.一起来看看 《Charlotte's Web》 这本书的介绍吧!

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具