资讯专栏INFORMATION COLUMN

通过类名动态生成对象

VEIGHTZ / 2607人阅读

摘要:保持目前的情况,除动态生成实例时需要完全限定类名,并无其他槽点。本文所讨论的根据类名动态生成对象,就要无视当前所在或引入的名字空间,必须使用完全限定类名形式。作为对比,不能动态生成对象。

转载请注明文章出处:https://tlanyan.me/dynamic-ne...
问题

前几天有人在PHP的QQ群里问生成对象的问题:

use AB;
$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的行为,让其根据当前上下文判断?

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

class_existsReflectionClass都没有指示程序上下文Context的参数;

PHP比较坑的一点:类名不会像函数、常量一样往上逐级查找;

如果存在多个同名的类,加载哪个?如以下代码所示:

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

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

总结

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

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

参考

PHP回顾之反射

PHP中的重载

Using namespaces: fallback to global function/constant

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30910.html

相关文章

  • 【干货】JDK动态代理的实现原理以及如何手写一个JDK动态代理

    摘要:代理模式从类型上来说,可以分为静态代理和动态代理两种类型。然而今天的重点是我们都知道牛逼轰轰的的实现的一种方式是使用的动态代理另一种是,大部分人也会用的动态代理,不过没有研究过的动态代理到底是怎么实现的。 动态代理 代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位。代理模式从类型上来说,可以分为静态代理和动态代...

    forsigner 评论0 收藏0
  • Java动态代理深度解析

    摘要:动态代理深度解析引言说起动态代理,很多人可能都没有直接去使用过。因为的动态代理只能代理接口,而不能代理原始的类。接下来是真正压轴的环节,实现自己的动态代理类。 Java动态代理深度解析 引言 说起动态代理,很多人可能都没有直接去使用过。但是只要用过Spring,那动态代理就是一个是个绕不过的坎,因为Spring的核心特性之一AOP就是基于动态代理来实现的,那么什么情况下需要用到动态代理...

    whinc 评论0 收藏0
  • 如何根据动态SQL代码自动生成DTO

    摘要:如何修改代码为了尽量减少程序员的工作,我们的代码生成器在生成完后,还需要将方法的返回值自动修改成这个类。具体的实现到此为止,基本上代码生成器的主要障碍都有了相应的处理办法。 当前的状况 一般做数据库相关开发, 除非学习, 否则很少有人愿意直接使用JDBC。本来Java代码就比较啰嗦了,而直接用JDBC写代码之啰嗦简直有些令人发狂!所以在实际开发过程中,我们通常都会使用一些框架/库来帮助...

    weij 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<