Използване на 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, така че да има повече място за добавяне на персонализирани подпроцеси, като регистриране защо техниката не работи, актуализиране на потребителски интерфейс, за да отразява "a по-дълго от обичайното време на задържане", или каквото и да е друго. Така че предполагам, че ще бъде нещо като:

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 multi-catch, където не се влагат опитите, а се отчитат различни изключения, които единият метод може да хвърли. Но използването на верижния 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 {
    $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;
}

РЕДАКТИРАНЕ: След като прочетох вашите коментари за други отговори

Предлагам ви алтернативно решение въз основа на казаното от вас. Разбирайки, че $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