以下是我的 Win7 机器上使用 PHP 5.3.6 的 Zend 调试器报告的代码结果:
如您所见,对您的呼叫__get
方法比常规调用慢很多(3-4 倍)。我们仍然处理总共 50k 次调用的不到 1s 的时间,因此在小规模使用时可以忽略不计。但是,如果您的目的是围绕魔术方法构建整个代码,您将需要分析最终的应用程序以查看它是否仍然可以忽略不计。
关于相当无趣的性能方面就这么多了。现在让我们看看您认为“不那么重要”的内容。我要强调这一点,因为它实际上比性能方面重要得多。
关于您所写的不必要的复杂性
它并没有真正增加我的应用程序的复杂性
当然可以。通过查看代码的嵌套深度,您可以轻松发现它。好的代码留在左边。你的 if/switch/case/if 有四层深。这意味着有更多可能的执行路径,这将导致更高的结果圈复杂度 http://phpmd.org/rules/codesize.html,这意味着更难维护和理解。
这是 A 类的数字(不包括常规 Getter。输出缩短为PHPLoc https://github.com/sebastianbergmann/phploc):
Lines of Code (LOC): 19
Cyclomatic Complexity / Lines of Code: 0.16
Average Method Length (NCLOC): 18
Cyclomatic Complexity / Number of Methods: 4.00
值为 4.00 意味着这已经处于中等复杂度的边缘。每增加一个案例到交换机中,这个数字就会增加 2。此外,它会将您的代码变成程序混乱,因为所有逻辑都在 switch/case 内部,而不是将其划分为离散单元,例如单吸气剂。
Getter,即使是延迟加载的 Getter,也不需要相当复杂。考虑与普通旧 PHP Getter 相同的类:
class Foo
{
protected $bar;
public function getBar()
{
// Lazy Initialization
if ($this->bar === null) {
$this->bar = new Bar;
}
return $this->bar;
}
}
在此运行 PHPLoc 将为您提供更好的循环复杂度
Lines of Code (LOC): 11
Cyclomatic Complexity / Lines of Code: 0.09
Cyclomatic Complexity / Number of Methods: 2.00
对于您添加的每一个普通旧 Getter,该值将保持为 2。
另外,请考虑到,当您想使用变体的子类型时,您将必须重载__get
并复制并粘贴整个 switch/case 块以进行更改,而使用普通的旧 Getter,您只需重载需要更改的 Getter。
是的,添加所有 Getter 需要更多的打字工作,但它也更简单,最终会产生更易于维护的代码,并且还有一个好处是为您提供显式 API,这使我们可以看到您的其他语句
我特别希望我的 API 是“隔离的”;该文档应该告诉其他人如何使用它:P
我不知道你所说的“隔离”是什么意思,但如果你的 API 无法表达它的作用,那么它就是糟糕的代码。如果我必须阅读你的文档,因为你的 API 没有告诉我如何通过查看它来与之交互,那么你就做错了。你正在混淆代码。在数组中声明属性而不是在类级别(它们所属的位置)声明它们会迫使您为其编写文档,这是额外且多余的工作。好的代码易于阅读并且具有自记录功能。考虑购买罗伯特·马丁的书《干净的代码》。
话虽如此,当你说
唯一的原因就是api的美观;
然后我说:那就不要使用__get
因为它会产生相反的效果。它会使 API 变得丑陋。魔法是复杂且不明显的,这正是导致那些 WTF 时刻的原因:
现在结束:
我没有看到任何真正的缺点,我想这是值得的
希望你现在就能看到他们。这不值得。
有关延迟加载的其他方法,请参阅Martin Fowler 的 PoEAA 中的各种延迟加载模式 http://martinfowler.com/eaaCatalog/lazyLoad.html:
延迟加载有四种主要类型。延迟初始化使用特殊的标记值(通常为空)来指示字段未加载。每次访问该字段都会检查该字段的标记值,如果已卸载,则加载它。虚拟代理是一个与真实对象具有相同接口的对象。第一次调用它的一个方法时,它会加载真实的对象,然后进行委托。价值持有者是一个具有 getValue 方法的对象。客户端调用getValue来获取真实的对象,第一次调用会触发加载。 Aghost是没有任何数据的真实对象。第一次调用方法时,ghost 会将完整数据加载到其字段中。
这些方法略有不同,并且有不同的权衡。您还可以使用组合方法。本书包含完整的讨论和示例。