Страницы

Поиск по вопросам

суббота, 30 ноября 2019 г.

Switch case final в PHP или почему goto это плохо

#php #архитектура #инспекция_кода


Проблема

Есть задача при использовании switch у разных case выполнять еще и код из default
(или например final реализовать), что бы не дублировать одинаковый код в разных кейсах.

switch ("b") {
    case 'a':
    case 'z':
    case 'q':
        echo "a\n"; // not need run default action
        break;
    case 'b':
        echo "b\n"; // need run default case without case 'c'
        break;
    case 'c':
        echo "c\n";
    default:
        echo "default"; // need run for "b" & "c" cases
}


Выводит:

b


А хотелось бы:

b
default


Если убрать break у варианта b, то будет выполнен лишний код

b
c
default


Есть решение через goto, что является плохим стилем кодирования:

switch ("b") {
    case 'a':
        echo "a\n";
        break;
    case 'b':
        echo "b\n";
        goto caseFinal;
        break;
    case 'c':
        echo "c\n";
        goto caseFinal;
        break;
    default:
        caseFinal:
        echo "default";
}


Полная задача

Есть массив полей разных сущностей и нужно разные действия у разных полей сделать.

switch ($fieldName) {
    case 'id': // не нужно default
        unset($properties['actions']['create']);
        unset($properties['actions']['edit']);
        break;
    case 'content':
        // одинаковый код нужно вынести в defaut
        unset($properties['actions']['dashboard']);
        // ...
        break;
    case 'isDeleted':
        // одинаковый код нужно вынести в defaut
        unset($properties['actions']['dashboard']);
        // ...
        break;
    default:
        // код нужне для всех остальных полей + кейсы выше
        unset($properties['actions']['dashboard']);
}


Вопрос

Как это сделать без использования goto? Может есть вариант с другим подходом в архитектуре.

P.S. Если goto здесь уместен (лично я не боюсь динозавров), то почему это плохой
стиль кодирования?
    


Ответы

Ответ 1



Зачем усложнять? Можно вынести повторяющийся код в функцию/метод класса и вызывать их из каждого кейса. Кода получится ровно столько же, зато goto мы не используем и код остаётся читаемый и легко поддерживаемый: function someAction() { //some code } switch ($fieldName) { case 'id': unset($properties['actions']['create']); unset($properties['actions']['edit']); break; case 'content': someAction(); unset($properties['actions']['dashboard']); // ... break; case 'isDeleted': someAction(); unset($properties['actions']['dashboard']); // ... break; default: someAction(); unset($properties['actions']['dashboard']); }

Ответ 2



Если только одно действие не должно быть продолжено default, почему бы не попробовать вынести default действие за switch и огородить if ($fieldName != 'id') { unset($properties['actions']['dashboard']); }

Ответ 3



Можно оформить условия как отдельные функции (методы). Ключевая функция. Получает действие на входе и выполняет соответствующую функцию: function make($action) { if ($action()) $default(); return; } Собственно действия. Возвращают true или false как маркеры необходимости выполнять действие по умолчанию. function a() { echo "a\n"; return false; // дефолтное действие выполнять не нужно } function b() { echo "b\n"; return true; // дефолтное действие выполнить нужно } Функция (метод) для действия по умолчанию: function default() { echo 'default'; return; } Используем: make('a');

Ответ 4



После изучения ответов, статей и умозрительных эксперементов, пришел к выводу. Вывод В данном случае использование goto допустимо, пока не будет добавлена подобная конструкция в синтаксис switch и если соблюдаются условия: Ты уже не Junior Переходить можно только вперёд Заходить в блоки и выходить категорически нельзя Любой while и вложенные if так же опасны как goto. Для выхода из множественных циклов есть break N. Плюсы которые я вижу Краткость и простота кода при соблюдении вышеописанных условиях Меньше занимаемой памяти и скорее всего быстрота выполнения Лучше "плохой тон", чем много избыточного кода, который сложнее поддерживать Для себя я решил использовать только в группах исключающих условий: switch ("b") { case 'a': echo "a\n"; break; case 'b': echo "b\n"; goto caseFinal; break; case 'c': echo "c\n"; goto caseFinal; break; default: caseFinal: echo "default"; } Конечно при усложнении логики и увеличении строк кода, лучше всего воспользоваться ответом n4nn31355 и выносить в классы и отдельные методы, но внутри у них все равно наверно будет что-то похожее ;) Интересные статьи на эту тему: Запретный плод GOTO сладок GOTO or not GOTO вот в чём вопрос

Ответ 5



Усугубим goto ... if (b == 'a') { echo "a\n"; goto done; } else if (b == 'b') { echo "b\n"; goto default; } else if (b == 'c') { echo "c\n"; goto default; } default: echo "default"; done: ... И кто скажет что это отвратительно - тот просто ничего не сечёт в программировании:)

Комментариев нет:

Отправить комментарий