通过类名动态生成对象

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

内容简介:前几天有人在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

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

查看所有标签

猜你喜欢:

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

我在阿里做运营

我在阿里做运营

芮曦(@小马鱼) / 电子工业出版社 / 2018-7 / 59.00元

《我在阿里做运营》是一本散发着浓浓阿里味儿的运营书。作者进入互联网行业7年,曾就职于携程、阿里巴巴等大平台,也服务过小微企业、传统企业及诸多职场新人。不仅经历过各类运营岗,也经历过市场、品牌等岗位,对精细化运营、数据化运营和低成本运营有着深刻见解。 本书展示了在阿里这样的大平台做运营工作的真实场景,也提炼了适用于小微企业的经验,以及让运营新人快速上手的技能和自我修养、职业规划。一起来看看 《我在阿里做运营》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

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

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具