Использование try/catch через php вместо вложенного if/else

Я видел несколько вопросов, касающихся этой темы, но я думаю, что у меня более фундаментальная нехватка того, как лучше всего использовать блоки try/catch, помимо самых простых примеров.

В этом конкретном случае у меня есть ряд методов для решения проблемы, от простого к довольно сложному, и я имею в виду что-то вроде:

if ($zombie_killer -> board_with_nail == 'failed') {
    if ($zombie_killer -> machette == 'failed') {
       if ($zombie_killer -> shotgun == 'failed') {
           $this -> panic;
       }
    }
}

Но вместо этого я подумал, что может быть лучшим подходом использовать блок try/catch, чтобы было больше места для добавления пользовательских подпроцессов, таких как ведение журнала, почему метод не работает, обновление пользовательского интерфейса для отражения «аварии». больше, чем обычно время удержания», или что-то еще. Так что я предполагаю, что это будет что-то вроде:

try {
    $zombie_killer -> board_with_nail;
}
catch(Exception $e) {
    try {
        $zombie_killer -> machette;
    }
}

Но это не намного лучше, и, учитывая всю обратную реакцию, которую другие получили с «что лучше, если/иначе или попробовать/поймать», я совершенно ясно понимаю, что, по крайней мере, есть большие различия и причины для их использования. . Вот почему я спрашиваю об этом варианте использования, потому что мне кажется, что с ним лучше всего справляется попытка/поймать, но я не могу понять, чувствует ли он себя плохо, потому что я действительно не использовал их много или потому что я не подходим к этому правильно.


person Anthony    schedule 07.08.2012    source источник
comment
Есть ли причина не использовать if(($zombie_killer -> board_with_nail == 'failed') && ($zombie_killer -> machette == 'failed') && ($zombie_killer -> shotgun == 'failed')) ?   -  person Mahn    schedule 07.08.2012


Ответы (3)


С личной точки зрения, я думаю, что, в отличие от if/else, try/catch предназначены для обработки исключений, а не вариантов использования, поэтому их лучше использовать для этого, а не для обработки того, что вы хотите сделать в зависимости от ситуации.

person Oussama Jilal    schedule 07.08.2012

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

function kill_zombie($weapon) {
    if (!$weapon instanceof FireArm && !$weapon instanceof HeavyObject)
        throw new Exception("Zombies can only be killed with firearms and heavy objects");
    // ...
}
person lafor    schedule 07.08.2012
comment
Хорошо, это имеет смысл, особенно если привязать его к примеру elxordi с readDatabase мульти-уловами, где он не вкладывает попытки, а учитывает различные исключения, которые может генерировать один метод. Но использование связанного if(!$zombie_killer-> board && !$zombie_killer -> machette) может быть более жестким, я пытаюсь оставить варианты свободными, так как для меня более важно, чтобы отдельные методы работали (или иным образом были открыты для обработки) и что у меня есть метод, который является одним -shot предложил использовать комбо, но сохранить детали общедоступными или, по крайней мере, защищенными, так что.. - person Anthony; 07.08.2012
comment
...можно попробовать другие комбинации или просто разовые попытки. Возможно, я ошибочно принимаю генерацию исключений как решение для открытия метода для готовности к подписке или отсутствия, поскольку я хочу, чтобы те, кто реализует библиотеку, также могли запускать подпрограммы на основе любого заданного результата. Так что, возможно, если $zombie_killer -> shotgun потерпит неудачу, они могут перезагрузить и повторить попытку, или вывести сообщение пользователю, или анимацию, или дать возможность выйти. В основном мне нравится идея, что это серия попыток или попыток, которые кажутся состояниями, а не состояниями, которые кажутся безстоящими. или я просто странный? - person Anthony; 07.08.2012
comment
Просто улучшил мой ответ. Кстати, пожалуйста, выберите окончательный правильный ответ. - person elxordi; 14.08.2012

Философия try/catch не та, которую вы описали. Хороший способ использовать его — перехватывать различные исключения в зависимости от того, какая ошибка произошла. Например:

try {
    $value = readDatabase();
    writeDatabase($++value);
} catch (ReadErrorException $e) {
    // do something
} catch (WriteErrorException $e) {
    // do something
}

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

Например, ваш код может стать:

if (
    $zombie_killer -> board_with_nail == 'failed'
    && $zombie_killer -> machette == 'failed'
    && $zombie_killer -> shotgun == 'failed'
) {
    $this -> panic;
}

Кроме того, хорошим способом было бы использование логических значений в качестве атрибутов:

if (
    !$zombie_killer -> board_with_nail
    && !$zombie_killer -> machette
    && !$zombie_killer -> shotgun
) {
    $this -> panic;
}

EDIT: после прочтения ваших комментариев к другим ответам

Я предлагаю вам альтернативное решение, основанное на том, что вы сказали. Понимая, что $zombie_killer — это класс, вы можете создать публичный метод с именем, например, kill(). Этот метод может получить доступ к общедоступным, частным и защищенным атрибутам класса.

Сначала я напишу пример без исключений.

Внутри класса:

public function kill()
{
    if ($zombie_killer -> board_with_nail != 'failed') return true;
    if ($zombie_killer -> machette != 'failed') return true;
    if ($zombie_killer -> shotgun != 'failed') return true;

    return false;
}

В другом файле, о котором мы говорили:

if (!$zombie_killer->kill()) {
   $this->panic;
}

Как вы можете видеть, код стал более чистым, а поведение функции по умолчанию предполагает, что зомби не будет убит, а в исключительных случаях это произойдет, если один из методов, используемых для уничтожения зомби, увенчается успехом. Это противоположно тому, как мы обычно думаем: мы предполагаем, что можем убить зомби, и исключительный случай был бы, если бы все потерпело неудачу. Но это просто философский вопрос, вы можете изменить код, и он все равно будет работать.

Давайте посмотрим то же самое с исключениями.

Файл класса:

public function kill()
{
    if (
        $zombie_killer -> board_with_nail == 'failed' 
        && $zombie_killer -> machette == 'failed'
        && $zombie_killer -> shotgun == 'failed'
    ) {
        throw new NotKilledException();
    }
}

Другой файл:

try {
    $zombie_killer->kill();
} catch (Exception $e) {
    $this->panic;
}

Итак, вы видите? Исключительная версия в этом случае не очень помогает, потому что вы все равно должны выполнить вложенное условие if, потому что условие должно выполнить три разных типа уничтожения с ошибкой. Исключение — не убивать зомби. Потому что вы хотите, чтобы исключительный код $this->panic выполнялся.

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

person elxordi    schedule 07.08.2012