Magento 2-使用/避免使用吸气剂的良好实践?


21

Varien_Object(M1)和DataObject(M2)上的魔术吸气剂是常见的做法,但是使用Magento 2时,使用它会感到错误。

好:

  • 容易读/写

使用Magento 2,我们有两种新方法:

  • getDataByKey($key)
  • getDataByPath($path)

是否有充分的理由继续使用getData($key)或使用任何吸气剂?


编辑:

@Vinai谢谢。我没有提及该@method方法,因为我的方法大不相同。

它仅对IDE有帮助,对其他方面没有影响。

有几个mergedf PR是“微优化”的,例如在循环外(甚至对于小型阵列)强制转换为数组大小或(int)替代intval()数组大小。

另一方面,有

  1. 神奇的吸气剂,正如马吕斯(Marius)所说的那样有些“开销”。

    strtolower(trim(preg_replace('/([A-Z]|[0-9]+)/', "_$1", $name), '_'));
  2. getData($key) Mehtods还必须额外进行2-3次检查...

    • if ('' === $key) {
    • if (strpos($key, '/')) {
    • if ($index !== null) {

对于自己的代码,完全同意倾向于使用实际方法,但是在相同情况下,这是不可能的...例如,您创建了一个自定义事件...

$value = $observer->getVar_1();
$value = $observer->getData('var_1');
$value = $observer->getDataByKey('var_1');

/** @var some $value */对我来说,最好使用3rd 。(?)


1
您可以在doc bloc类中添加方法,以使代码分析工具不会抱怨不存在的方法。我也认为在键中使用数字本身是一种不好的做法,因此在imo中不应将其列为“错误”。
Lily Bergonzat

Answers:


20

上面的问题是关于使用魔术方法vs getDataByKeygetDataByPath。我认为还有第三种选择,那就是实现真正的getter和setter方法。

getData*方法都有不足之处,他们必须要进行注释的类型推断的工作。
通常,这是通过调用/* @var string $foo */上方的注释来完成的getData*
这有点令人讨厌,因为数据类型应在包含数据的类中声明,而不是在调用的类中声明getData*
这样做的原因是,如果数据发生更改,则最有可能更新类,而不是所有getData*调用站点。
这就是为什么我认为真正的方法增加维护与使用getData*存取。

因此,我认为这归结为可维护性与更快的实现(更少的代码编写)之间的权衡。

幸运的是,如今,IDE非常擅长为我们创建getter和setter实现,因此该论点不再适用。

上面的问题缺少针对魔术获取器和设置器的另一种说法,那就是无法为它们创建插件。

我认为我可以添加到该主题的唯一其他值是@method,如果由于某些原因无法实现真正的方法,则尝试收集使用或不使用注释的原因。

优点

  • 一个@method注释是少一点的代码来写相比,实现真正的getter和setter。如今,这几乎是不对的,因为IDE擅长生成访问器方法,因此这不再是真正的好处。

缺点

  • 事情容易出错。
    • 注释是注释,当代码发展但注释不更新时,它们很容易过时。实际方法更健壮。
    • 可以添加多个具有不同类型签名的注释而不会导致解释器错误-静态代码分析行为是未定义的,并且可能导致难以跟踪的细微错误。
    • 如果同时存在一个@method注释和一个具有相同名称的真实方法,则注释类型签名将在静态代码分析期间覆盖该真实方法,这与PHP解释器的操作相反。这又很容易导致细微的错误。

由于上述原因,@method如果可以避免的话,我个人不使用注释。
对于打算长期使用的代码,我实现了真正的getter和setter方法。增强可维护性值得触发IDE生成它们。

对于尖峰期间的更多实验代码,或者对于模块的简单实现细节,我也使用getData*方法,因为我很懒。


不错的总结。谢谢Vinai。这比我实际要求的答案要多。
sv3n

1

getData*方法都有不足之处,他们必须要进行注释的类型推断的工作。

通常,这是通过调用/*@var string $foo */上方的注释来完成的getData*。这有点令人讨厌,因为应该在包含数据的类中声明数据的类型,而不是在调用getData *的类中声明。

这样做的原因是,如果数据发生更改,则最有可能更新类,而不是所有getData*调用站点。这就是为什么我认为与使用getData *访问器相比,真正的方法可以提高可维护性。

是的,它很臭,但可以(并且应该避免)。我认为这是非常常见的代码,经常建议:

/** @var Foo $product */
$product = $model->getProduct()
if ($product->getId()) {
    $product->doSomething();
}

问题在于您只是猜测返回值是Foo带有可调用getId()方法的类型。

为了可维护性,为什么不假设变量类型并添加一个InvalidArgumentException

$product = $model->getProduct()
if ($product instanceof Foo && $product->getId()) {
    $product->doSomething();
}

这也可以修复$model->getProduct()具有不同返回类型(例如)的情况下的静态代码分析Foo|false。在第一种情况下,它会抱怨呼吁doSomething()可能false

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.