Стандарт 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
) {
}
Ответы
Ответ 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
Это всего лишь пример, для чего-то простого, такого как определение строки, вы должны использовать регулярное выражение.