Как реализовать множество условий?

Подскажите пожалуйста по следующему вопросу:
Есть скрипт, который работает с БД, результат работы зависит от принятых (POST) параметров (параметр-значение)
Параметров несколько, некоторые зависят от других (если параметр N1,тогда также проверять параметры N2,N3, если параметр N2, то проверять параметры N5,N10 (для примера)).
Значения некоторых параметров могут принимать только определенные значения, иначе ошибка.
Скрипт сделал, он работает, но получится убогий костыль с кучей if`ов и else, самому противно смотреть.
Собственно вопрос, как можно реализовать проверку входящих данных на соответствие нужным условиям без кучи if`ов?
  • Вопрос задан
  • 232 просмотра
Решения вопроса 1
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
Итак... возьмем ваш код

if (!preg_match("/^[a-zA-Z0-9_]+$/", $username)) die("Bad login");
        if (
        $type != 'voice' and $type != 'balance1' and $type != 'balance2' and $type != 'absvoice' and $type != 'passhash' and
        $type != 'paytime' and $type != 'white1' and $type != 'exp1' and $type != 'white2' and $type != 'voice2' and
        $type != 'exp2') die("Wrong type");
        if ($action != 'set' and $action != 'get' and $action != 'add') die("Wrong action");
        if ($action == 'set' and !(preg_match("/^[0-9-.]+$/", $value)) and $type != 'passhash') die("Wrong value");
        if (($action == 'set' or $action == 'add') and ($type == 'paytime' OR $type == 'absvoice')) die("paytime/absvoice read only");
        if (($action == 'add') and ($type == 'passhash' or $type == 'white1' or $type == 'white2')) die("add not available for this");


первое что мы можем тут увидеть - дублирование условий, у нас много примерно одинаковых условий. Давайте упростим все используя in_array

if (!preg_match("/^[a-zA-Z0-9_]+$/", $username)) die("Bad login");

$availableTypes = ['voice', 'balance1', 'balance2', 'absvoice', 'passhash', 'paytime', 'white1', 'exp1', 'white2', 'voice2', 'exp2'];
if (!in_array($type, $availableTypes)) {
    die("Wrong type");
}

if (!in_array($action, ['set', 'get', 'add'])) {
    die("Wrong action");
}
if ($action == 'set' and !(preg_match("/^[0-9-.]+$/", $value)) and $type != 'passhash') {
    die("Wrong value");
}
if (($action == 'set' or $action == 'add') and in_array($type, ['paytime', 'absvoice'])) {
    die("paytime/absvoice read only");
}
if (($action == 'add') and (in_array($type, ['passhash', 'white1', 'white2']))) {
    die("add not available for this");
}


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

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

updated: избавляемся от всех ифов (точнее заменяем на один)
$constraints = [
    'unsupportedTypes' => !in_array($type, $availableTypes),
    'unsupportedAction' => !in_array($action, ['set', 'get', 'add']),
    'expectedNumericValue' => $action == 'set' && is_numeric($value),
    'readOnlyType' => 'get' !== $action && in_array($type, ['paytime', 'absvoice']),
    'disallowedTypes' => 'add' === $action && in_array($type, ['passhash', 'white1', 'white2']),
];

$constraintsMessages = [
    'unsupportedTypes' => 'Type "<type>" is not supported',
    'unsupportedAction' => 'Action "<action>" is not supported',
    'expectedNumericValue' => 'Wrong value, expected numeric',
    'readOnlyType' => '<type> is read only',
    'disallowedTypes' => 'Type "<type>" is not supported for action "<action>"'
];

$errors = array_keys(array_filter($constraints));
if (!empty($errors)) {

    die(str_replace(
        ['<type>', '<action>'],
        [$type, $action],
        $constraintsMessages[reset($errors)]
    ));
}


это дело можно еще упростить и соорудить нормальные правила валидации + отдельную функцию которая будет проверять все это дело.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
magalex
@magalex
Архитектор распределённых систем управления
Как вариант воспользоваться функцией in_array и 2 и 3 условия сделать такими:
if( !in_array( $type, ['voice', 'balance1', 'balance2', ...] ) ) die("Wrong type");
if( !in_array( $action, ['set', 'get', 'add'] ) ) die("Wrong action");


конструкцию
if($type == 'balance1' || $type == 'voice' || $type == 'voice2' || $type == 'balance2')

заменить на
if( in_array( $type, ['balance1', 'voice', 'voice2', 'balance2') )


остальное заменить аналогично
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы