【问题标题】:PSR-2 standard for long if-conditions长 if 条件的 PSR-2 标准
【发布时间】:2014-05-20 11:44:41
【问题描述】:

我没有找到这个案例的任何标准:

if ($a == $b && $b == $c && $c == $d && $g == $d) {

}

if (($a == $b && $b == $c) && ($c == $d && $g == $d)) {

}

想象一下 var-names 更长并且超过了 80 个字母。我该如何处理? 它可能看起来像:

if (
       $a == $b
    && $b == $c
    && $c == $d
    && $g == $d
) {

    }

【问题讨论】:

  • 您也可以将其缩短为$a == $g
  • 我不相信有任何 PSR 定义在这种情况下应该使用什么标准;尽管 Zend 等其他编码标准有自己的规则,通常建议使用缩进拆分多行,而括号是代码逻辑和可读性的问题
  • 这在我看来是个特例,请这样对待。
  • @Daan 这只是一个例子,我没有任何情况可以像这样比较
  • @Daan 不,即使$c 不等于$d,您的条件也会评估为真。另外,你完全没有抓住重点。

标签: php convention


【解决方案1】:

对于这种情况没有建议/约定,正如 Halcyon 已经提到的,这是一个非常特殊的情况。

但是,建议使用一长串参数的函数调用:

参数列表可以分成多行,其中每行 后续行缩进一次。这样做时,第一项在 列表必须在下一行,并且每个必须只有一个参数 行。

<?php
$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);

因此,如果我必须创建一个类似于您的 if 语句,我会这样做:

if (
    $a == $b &&
    $b == $c &&
    $c == $d &&
    $g == $d
) {
    // do something
}

如您所见,这与您自己提出的解决方案几乎相同,但我更喜欢在条件后添加 &amp;&amp; 运算符。

【讨论】:

  • 我不明白这个标准的制定者怎么没有解决方案。这让我患上了眼癌
  • 这绝对不是一个非常特殊的案例!如果你坚持分成 80 个字符的几行,这种情况经常发生!
  • 如果我必须这样做,我会将一级运算符放在前面,因为有时您可能会遇到嵌套条件,您可能希望将它们保持在同一行。
  • phpcs 2.5.0 与 psr2 标准说:Expected 0 spaces after opening bracket; newline found。所以这似乎不是有效的 psr2。下面的 Maurice 变体适用于代码嗅探器。
  • 比较运算符应该在行中的第一位,并且在左括号之后应该没有空格。 pear.php.net/manual/en/…
【解决方案2】:

个人比较喜欢

if ($a == $b
    && $b == $c
    && $c == $d
    && $g == $d
) {
    // code here...
}

对于每一行,都以双 & 号开头,表示以下语句与其他语句是分开的。如果将 & 符号放在行尾,则当行的长度变化很大时,它可能会变得不那么明显。

例如;

if ($a == $b && 
    $b == $c && 
    $thisisamuchlongerstatementbecauseofthisvar == $d && 
    $g == $d
) {
    // code here...
}

在这种情况下,您必须更多地扫描代码才能知道每条线是由双&符号连接的。

【讨论】:

  • 我实际上更喜欢你的答案而不是接受的答案。它在视觉上看起来还不错——只是还不错,因为第一行与众不同——同时也适用于 PSR2。双与号的论点也很有说服力,我可能会改用这种风格。 :)
  • 此外,接受的答案不是 psr-2 有效的(如果我可以信任“squizlabs/php_codesniffer”)。
  • 这种方法还可以更轻松地注释掉特定条件,因为它与操作符在同一行
【解决方案3】:

值得一提的是,取代 PSR-2 的新标准 PSR-12 澄清了这个问题。

括号中的表达式可以分成多行,其中每个后续行至少缩进一次。这样做时,第一个条件必须在下一行。右括号和左大括号必须放在各自的行上,它们之间有一个空格。条件之间的布尔运算符必须始终位于行首或行尾,而不是两者的混合。

<?php

if (
    $expr1
    && $expr2
) {
    // if body
} elseif (
    $expr3
    && $expr4
) {
    // elseif body
}

来源:https://www.php-fig.org/psr/psr-12/#51-if-elseif-else

【讨论】:

  • 这应该是公认的答案,因为它不是基于个人观点,而是从官方来源链接中引用并确认的。
【解决方案4】:

编辑

一年后,我强烈建议您重写代码以缩短 if 语句。通过变量或函数调用。

原创

我遇到了这种情况,所以我决定采用以下格式:

if (
    $a == $b &&
    $b == $c &&
    $c == $d &&
    $g == $d) {
}

但是,我使用 phpcbf,它将(遵循 PSR2 标准)之前的代码转换为:

if ($a == $b &&
    $b == $c &&
    $c == $d &&
    $g == $d) {
}

我想知道更多:如果它没有写在任何地方,它怎么知道这是标准所期望的行为?嗯,答案很简单:按照标准考虑案例,通过下面这句话:

左括号后不能有空格

这解释了为什么第二个 sn-p 是唯一的一个,它遵循 php-fig 声明的 PSR-2 标准。

【讨论】:

    【解决方案5】:

    我更喜欢将逻辑运算符放在行首的长 if 语句中,主要是为了可读性和更好的版本控制行为。

    请注意,正如其他答案中也提到的那样,长 if 语句通常是一种代码味道。但是有时你必须这样做,或者代码已经存在并且你不能重写它,所以如果它已经是一件坏事,那么它有助于不要造成更多的混乱。

    这些东西也适用于只有一个“and”的 if 语句,其中不同的元素很长,你仍然需要将它分成多行(例如长变量或类名)。

    if (
        $something->getValue() === 'some_value'
        || (
            $something instanceof SomeClass
            && $something->has($someNumber)
            && $someNumber > 42
        )
    ) {
        // do something
    }
    

    可读性:由于所有逻辑运算符都是垂直分组的,因此您可以立即查看每行中的运算符。当你的眼睛扫描代码时,它可以直接垂直移动,只有在实际存在额外逻辑层时才需要水平移动。

    如果操作员位于线路的末端,您的眼睛需要在长度不均匀的线路之间随机来回移动。

    版本控制中的更好行为:当在 if 语句的底部添加额外的子句时,这将转换为版本控制中添加 1 行并删除 0 行。

    diff --git a/3.php b/3.php
    index 367c57c..2a40c3a 100644
    --- a/3.php
    +++ b/3.php
    @@ -6,6 +6,7 @@ 
        if (
             $something instanceof SomeClass
             && $something->has($someNumber)
             && $someNumber > 42
    +        && $anotherCase
        ) {
         // do something
    

    如果您将逻辑运算符放在末尾,则将添加 2 行并删除 1 行。这反过来又掩盖了有用的信息:当您进行 Git 注释时,您的最后一次更改的提交消息将显示在两行中,因此您必须转到以前的版本才能查看您添加运算符的行的提交消息。

    diff --git a/4.php b/4.php
    index f654780..2b9e0c5 100644
    --- a/4.php
    +++ b/4.php
    @@ -5,7 +5,8 @@ 
        if (
            $something instanceof SomeClass &&
            $something->has($someNumber) &&
    -       $someNumber > 42
    +       $someNumber > 42 &&
    +       $anotherCase
         ) {
         // do something
    

    【讨论】:

      【解决方案6】:

      我最喜欢的方法是从 IF 语句中删除子表达式,如下所示:

      $c1 = $a == $b;
      $c2 = $b == $c;
      $c3 = $c == $d;
      $c4 = $g == $d;
      if ($c1 && $c2 && $c3 && $c4) {
      }
      

      这种方法也将使其更易于调试。

      由于associative property of the logic operators,您公开的第二种情况等同于第一种情况。所以$a &amp;&amp; $b &amp;&amp; $c($a &amp;&amp; $b) &amp;&amp; $c相同,与$a &amp;&amp; ($b &amp;&amp; $c)相同

      【讨论】:

      • 此代码与原始代码相同,因为它评估$c, $d, $g,即使$a != $b,因此只能在那些没有副作用的情况下使用。
      • 表演会有副作用。不管它是否可以接受......好吧,我不想养成这个习惯。
      • 我猜你总是可以退回到汇编代码以使事情变得更快......但这不是@Chicna的目的
      【解决方案7】:

      现在有一个推荐……在PSR-12

      括号中的表达式可以分成多行,其中每个后续行至少缩进一次。这样做时,第一个条件必须在下一行。右括号和左大括号必须放在各自的行上,它们之间有一个空格。条件之间的布尔运算符必须始终位于行首或行尾,而不是两者的混合。

      <?php
      
      if (
          $expr1
          && $expr2
      ) {
          // if body
      } elseif (
          $expr3
          && $expr4
      ) {
          // elseif body
      }

      【讨论】:

        【解决方案8】:

        我建议您尝试从不同的角度考虑操作。例如:

        if (count(array_unique([$a, $b, $c, $d, $g])) == 1)
        

        您可能会发现,您可以将整个算法表达为更多的对集合的操作,使用数组而不是单个变量,并对集合使用逻辑操作,如上所示。这可能会导致截然不同且更具可读性的代码。

        重构的另一个例子:

        namespace My;
        
        UnexpectedValueException::assertAllEqual($a, $b, $c, $d, $g);
        
        
        class UnexpectedValueException extends \UnexpectedValueException {
        
            public static function assertAllEqual(/* $value, ... */) {
                $args = func_get_args();
                if (count(array_unique($args)) > 1) {
                    throw new static(sprintf('[%s] are not all equal', join(', ', $args)));
                }
            }
        
        }
        

        【讨论】:

        • 问题是关于格式化长条件而不是关于这个特定条件。所以你的回答虽然有趣,但毫无用处。
        • 该建议同样适用于任何代码,仅在这个具体示例中进行演示。让我这样说吧:首先要避免长时间的条件。
        • @deceze 严肃的程序员首先会避免长条件。但是,如果必须有一个很长的条件,那么您的答案不会为问题增加任何价值。如果 OP 询问有关样式化长条件的问题,他确实熟悉一般的最佳实践。任何不熟悉的人都会在不考虑样式的情况下放弃该条件。
        【解决方案9】:

        我也更喜欢开头的:

        if (   self::LOG_ALL
            || (    self::DEBUG__EXECUTION_TIME__IS_ENABLED
                && (self::DEBUG__EXECUTION_TIME__THRESHOLD_SECONDS < $trxDurinationSeconds)
               )
        ) {
            doSomething();
        }
        

        【讨论】:

          【解决方案10】:

          我更喜欢这种风格:

          if (condition1
          || (condition2_1 
              && condition2_2
              && condition2_3)
          && (c3 && c4) {
              // do something
          }
          

          但同样,请让您的 if 尽可能简单。

          也许在多个 if 中分隔一个大条件是一个更好的主意。

          对于您的问题,我将创建一个函数,该函数接受一个数组并在满足所有 &amp;&amp; 时返回 true。然后,在我的主代码中你会喜欢

          $arr = [$a => $b, $b => $c, $c => $d];
          // or you can create array of arrays [[$a, $b], [$b, $c] ...]
          
          if (allTrue($arr))
              // do something
          

          【讨论】:

            猜你喜欢
            • 2015-02-02
            • 1970-01-01
            • 2015-11-01
            • 2015-08-31
            • 1970-01-01
            • 1970-01-01
            • 2015-08-24
            • 2018-03-03
            • 1970-01-01
            相关资源
            最近更新 更多