【问题标题】:Avoid using static access to Exception避免使用静态访问异常
【发布时间】:2013-09-06 06:19:22
【问题描述】:

我刚刚第一次启动了 PHPMD,可以预见的是,我遇到了一个我无法弄清楚的错误。错误是

避免使用静态访问类“InvalidArgumentException” 方法“setLang”。

代码是

public function setLang($val0) {
    switch ($val0) {
    case ENG:
    case FRE:
    case SPA;
        $this->lang = $val0;
        break;
    default:
        throw new InvalidArgumentException("Invalid language choice.");
    }
}

我尝试了各种不同的方法,但我认为归根结底Exception 是一个静态工厂 (???),因此它必须具有静态访问权限。但是,PHPMD 的家伙肯定比我聪明,所以这不会让他们烦恼。

为什么会出现这个警告,如何解决?

【问题讨论】:

    标签: php exception testing code-cleanup phpmd


    【解决方案1】:

    如果您使用 XML 规则集,则可以从该规则中排除某些类(完整命名空间):

        <rule ref="rulesets/cleancode.xml">
            <exclude name="StaticAccess"/>
        </rule>
        <rule ref="rulesets/cleancode.xml/StaticAccess">
            <properties>
                <property name="exceptions" value="\Drupal\views\Views,\Drupal\Core\Access\AccessResult" />
            </properties>
        </rule>
    

    【讨论】:

      【解决方案2】:

      此警告背后的想法是,如果您使用 new 关键字在代码中嵌入类名,则很难在测试和模拟或存根方法中交换这些类,而被测代码可能会调用它们. See the explanation 在 PHPMD 规则中。

      我认为在您的情况下这是误报,因为异常通常本身并没有太多行为,但是它们的类名(及其背后的类层次结构)几乎是它们唯一重要的事情。

      如果你想摆脱这里的警告,你可以在这里使用@SupressWarnings注解。

      【讨论】:

      • 谢谢。那么,我可以关闭它,还是以某种方式避免它?
      • 哦,我应该说我只是改成了异常处理。之前我只是使用die(),但感觉不对。
      • 我对 PHPMD 不是很熟悉,但它应该理解 @SuppressWarnings 注释。
      【解决方案3】:

      因为我用了很多self::作为常量,把phpmd代码改成接受self::和parent::。

      在程序 PHP/PMD/Rule/CleanCode/StaticAccess.php 的第 36 行,更改为:

      if ($this->isReferenceInParameter($reference)
          || $reference->getImage() === 'self' 
          || $reference->getImage() === 'parent' 
          ) {
          continue;
      }
      

      也许你可以用它来改进代码。

      【讨论】:

        【解决方案4】:

        啊,经过一番挖掘,我直接从马的嘴里找到了答案。

        在位于yourphpdir\data\PHP_PMD\resources\rulesets 的配置文件中,cleancode.xml 具有解释设置的 CDATA cmets。

        这句话说:

        静态访问会导致对其他类的不可交换依赖,并且 导致难以测试代码。不惜一切代价避免使用静态访问 而是通过构造函数注入依赖项。唯一的案例 什么时候可以接受静态访问是用于工厂方法。

        解决的方法就是把异常作为参数传递,所以在类外声明。

        $foo->setLang("Oh noes!", new InvalidArgumentException("No lang for you."));
        

        【讨论】:

        • 是的,PHPMD 在这里成功地发现了对InvalidArgumentException 的隐藏依赖。然而,就像@complex857 在他的answer 中评论的那样,我会说这是一个边缘情况,因为抛出异常通常需要一个非注入的类名。就像在工厂中一样,异常类名是代码的属性,而不是可注入的依赖项(至少不是在这个低级别上)。你一开始就正确地替换了die()。专注于首先杀死所有die()s:D。
        • @hakre 的解释很好。但是,我必须同意这似乎是一个误报,因为您可能会从库例程中返回各种异常来指示问题(设置语言可能没有安装语言、用户安全、没有翻译等......)和异常因此可能是不同的类型,因此调用者可以根据问题继续/中止。我认为这需要在 PHP_MD 中进行调整以帮助忽略误报,因为我不想在代码中有很多 @SuppressWarnings(PHPMD.StaticAccess)。
        • @StevenScott:我觉得将其称为“误报”有点过于苛刻。由于 PHPMD 进行静态代码分析,它只能向您报告代码中违反(或被捕获)某些规则的点。由程序员阅读此输出并理解规则,然后决定做什么。静态代码分析永远不会对这些程序员步骤进行,它只是一种工具,可以帮助保持对整个代码库的概述。这么说,可能会有一些例外的规则是有意义的(有时)。
        • @hakre 关于“false positivi”的说法是正确的,但如果它导致自动构建出现一些问题,在删除删除之前会浪费大量时间,但在其他情况下可能仍然很有价值。
        • 我不会认为浪费时间。它要么是对已构建的更好配置,要么是在其他项目中使用的有价值的反馈。如果您每次都有此报告但您希望忽略它,那么在构建时不使用该检查可能是值得的。
        猜你喜欢
        • 1970-01-01
        • 2020-08-15
        • 1970-01-01
        • 1970-01-01
        • 2016-11-06
        • 2016-09-25
        • 2010-09-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多