Подтвердить что ты не робот

Стандарт PSR-2 для длинных условий if

Я не нашел никакого стандарта для этого случая:

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

}

или

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

}

Представьте, что имена var длиннее и превышено 80 букв. Как я должен справиться с этим? Это может выглядеть так:

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

    }
4b9b3361

Ответ 1

В этом случае нет рекомендации/конвенции, и, как уже упоминал Halcyon, это весьма исключительный случай.

Однако существует рекомендация для вызова функции с длинным списком параметров:

Списки аргументов МОГУТ быть разделены на несколько строк, где каждый последующая строка имеет один раз отступ. При этом первый элемент в список ДОЛЖЕН быть на следующей строке, и ДОЛЖНО быть только один аргумент за линия.

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

Итак, если бы мне пришлось создать оператор if, похожий на ваш, я бы сделал следующее:

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

Как вы можете видеть, это почти то же самое, что и предлагаемое вами решение, но я предпочитаю добавлять операторы && после условий.

Ответ 2

Лично я предпочитаю

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

Для каждой строки вы начинаете с двойного амперсанда, указывая, что следующий оператор является отдельным от других. Если вы поместите амперсанд в конец строки, это может стать менее очевидным, когда линии сильно различаются по длине.

Например:

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

В этом случае вам нужно больше сканировать код, чтобы знать, что каждая строка связана двойным амперсандом.

Ответ 3

Изменить

Через год я настоятельно рекомендую переписать ваш код, чтобы сделать его более коротким. С помощью переменных или вызовов функций.

Оригинал

Я попал в эту ситуацию, поэтому решил перейти в следующий формат:

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

Но я использую phpcbf, который преобразовал (следуя стандарту PSR2) предыдущий код в:

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

Я хотел бы знать больше: как он узнает, что это стандартное поведение, если оно нигде не написано? Ответ прост: случай учитывается стандартом следующим предложением:

Не должно быть пробела после открывающей скобки

Это объясняет, почему второй фрагмент является единственным и единственным, который соответствует стандарту PSR-2, как объявлено php-fig.

Ответ 4

Я предпочитаю помещать логические операторы в длинные операторы if в начале строки, главным образом для удобства чтения и лучшего поведения в управлении версиями.

Обратите внимание, что, как уже упоминалось в других ответах, код обычно пахнет длинными операторами if. Однако иногда вам приходится делать это, или код уже есть, и вы не можете переписать его, поэтому, если это уже плохо, это помогает не создавать еще больше беспорядка.

Также эти вещи применимы к операторам 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

Ответ 5

Мой любимый подход - удалить подвыражения из оператора IF следующим образом:

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

Этот подход облегчит отладку.

Второй случай, который вы выставляете, эквивалентен первому из-за ассоциативного свойства логических операторов. Следовательно, $a && $b && $c совпадает с ($a && $b) && $c, что совпадает с $a && ($b && $c)

Ответ 6

Я бы предложил вам подумать об операции в разных терминах. Например:

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)));
        }
    }

}

Ответ 7

Я также предпочитаю его в начале:

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

Ответ 8

Я предпочитаю делать это в таком стиле:

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

Но опять же, сохраняйте, если это как можно проще.

Может быть, лучше разделить большое условие на несколько if.

На ваш вопрос я бы создал функцию, которая принимает массив и возвращает true, если все && выполнены. Тогда в моем основном коде вы бы хотели

$arr = [$a => $b, $b => $c, $c => $d];
// or you can create array of arrays [[$a, $b], [$b, $c] ...]

if (allTrue($arr))
    // do something

Ответ 9

Стоит отметить, что новый стандарт PSR-12, означающий замену PSR-2, проясняет этот вопрос.

Выражения в скобках МОГУТ разбиваться на несколько строк, где каждая последующая строка имеет отступ по крайней мере один раз. При этом первое условие ДОЛЖНО быть на следующей строке. Закрывающая скобка и открывающая фигурная скобка ДОЛЖНЫ быть размещены вместе на отдельной строке с одним пробелом между ними. НЕОБХОДИМО, чтобы булевы операторы между условиями всегда были в начале или в конце строки, а не в обоих случаях.

<?php

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

Источник: https://www.php-fig.org/psr/psr-12/#51-if-elseif-else

Ответ 10

На мой взгляд, хороший способ сделать что-то вроде этого

function testString($string)
{
    // define the if criteria
    $criteria = [
        // 0: string starts with A
        substr($string, 0, 1) == 'A',
        // 1: string ends with Z
        substr($string, -1, 1) == 'Z',
        // 2: string length is 10
        strlen($string) == 10
    ];

    // if the array contains false, at leat one creteria failed
    return !in_array(false, $criteria);
}

Конечно, это можно использовать и без функции оболочки. Его действительно легко отладить: просто var_dump переменную $ attribute, и вы получите список того, что успешно, а что нет.

Результаты

testString('ABCDEFGXYZ')   // true
testString('ABCDEFXYZ')    // false
testString('BCDEFGHXYZ')   // false

Это всего лишь пример, для чего-то простого, такого как определение строки, вы должны использовать регулярное выражение.