Як ефективно використовувати спробу ... ловити блоки в PHP


78

Я використовував блоки try..catch у своєму PHP-коді, але не впевнений, чи правильно їх використовував.

Наприклад, деякий мій код виглядає так:

 try {
      $tableAresults = $dbHandler->doSomethingWithTableA();
      $tableBresults = $dbHandler->doSomethingElseWithTableB();
 } catch (Exception $e) {
      return $e;
 }

Отже, я групую кілька операцій над базою даних в одному блоці try / catch, тому що, якщо в будь-якій транзакції виникає будь-який виняток, я зможу це обробити.

Я роблю це так, бо вважаю, що це читабельніше та ефективніше, ніж:

 try {
       $tableAresults = $dbHandler->doSomethingWithTableA();
 } catch (Exception $e) {
       return $e;
 }
 try {
       $tableBresults = $dbHandler->doSomethingWithTableB();
 } catch (Exception $e) {
       return $e;
 }

Хоча, я не впевнений, чи те, що я роблю, є гарною практикою чи просто лінивим способом ловити винятки.

Я припускаю, що лише якщо виняток вимагає спеціальної обробки, він повинен мати власний блок try / catch, інакше групування їх у тому самому try / catch має бути нормальним.

Тож мої запитання:

Чи є якась перевага використання блоків try / catch для кожної транзакції бази даних? чи я все-таки можу без проблем згрупувати кілька транзакцій бази даних в одному блоці try / catch?

Чи добре вкладати блоки спроби / лову? Дякую!

РЕДАГУВАТИ

Оператор return був в основному лише для демонстрації, але я також використовую повернення, catch()оскільки я роблю запит AJAX до цього методу, а Javascript очікує об'єкт JSON, тоді, якщо виникає виняток, я повертаю порожній масив, закодований JSON . Я просто думав, що це не додасть жодного значення для введення конкретного коду в мій приклад.


У мене така сама відповідь. Це залежить! Чи взаємозалежні транзакції БД, чи FOREIGN KEYSзадіяні вони? Чи залежать транзакції в таблиці B від операцій у таблиці A? Це те, що вам потрібно запитати себе, щоб вирішити, можете ви їх згрупувати чи ні.
CodeAngry

Так, транзакції в таблиці B залежать від транзакцій у таблиці A. Отже, якщо транзакція A не вдається, транзакція B не повинна запускатися. Він може працювати, але все одно поверне порожній набір результатів.
ILikeTacos

6
Тоді зробіть їх групувати! Але пам’ятайте, ви повинні розуміти, що і для чого ви робите. Просто подумайте так ... як тільки я кину, чи потрібні мені наступні рядки коду для виконання? Якщо ні, помістіть їх у try{}блок. Ті, що я роблю ... продовжують після catch(){}закінчення.
CodeAngry

Відповіді:


90

Важлива примітка

Наступне обговорення передбачає, що мова йде про код, структурований як у прикладі вище: незалежно від того, яку альтернативу обрано, виняток призведе до того, що метод логічно припинить робити те, що було в середині.


Поки ви маєте намір робити те саме, незалежно від того, який оператор у tryблоці видає виняток, тоді, звичайно, краще використовувати одиницю try/ catch. Наприклад:

function createCar()
{
    try {
      install_engine();
      install_brakes();
    } catch (Exception $e) {
        die("I could not create a car");
    }
}

Кілька try/ catchблоків корисні, якщо ви можете і маєте намір впоратися з несправністю способом, специфічним для того, що саме її спричинило.

function makeCocktail()
{
    try {
        pour_ingredients();
        stir();
    } catch (Exception $e) {
        die("I could not make you a cocktail");
    }

    try {
        put_decorative_umbrella();
    } catch (Exception $e) {
        echo "We 're out of umbrellas, but the drink itself is fine"
    }
}

4
Не забувайте, що PHP5.5 додав підтримкуfinally
Mike Mackintosh

21

Для нащадків відповідь може бути занадто пізньою. Вам слід перевірити, чи повертається значення змінної, і викинути виняток. У такому випадку ви будете впевнені, що програма перейде з того місця, де виняток піднімається, до блоку catch. Знайдіть нижче.

try{
   $tableAresults = $dbHandler->doSomethingWithTableA();
   if (!tableAresults) 
     throw new Exception('Problem with tableAresults');

  $tableBresults = $dbHandler->doSomethingElseWithTableB();
   if (!tableBresults) 
     throw new Exception('Problem with tableBresults');
} catch (Exception $e) {
    echo $e->getMessage();

}

9

Це легше читати за один прийом блоку catch. Якщо важливо виявити помилку, я рекомендую налаштувати винятки.

try {
  $tableAresults = $dbHandler->doSomethingWithTableA();
  $tableBresults = $dbHandler->doSomethingElseWithTableB();
} catch (TableAException $e){
  throw $e;
} catch (Exception $e) {
  throw $e;
}

7

Немає жодної причини проти використання одного блоку для декількох операцій, оскільки будь-який викинутий виняток перешкоджатиме виконанню подальших операцій після невдалої. Принаймні до тих пір, поки ви зможете зробити висновок про те, яка операція не вдалася, з вилученого винятку. Це поки це нормально, якщо деякі операції не виконуються обробляються.

Однак я б сказав, що повернення винятку має лише обмежений сенс. Повернене значення функції повинно бути очікуваним результатом певної дії, а не винятком. Якщо вам потрібно зреагувати на виняток у області виклику, тоді або не вловлюйте виняток тут усередині вашої функції, а в області виклику або повторно викиньте виняток для подальшої обробки після того, як зробили деякі журнали налагодження тощо.


6

Коли виникає виняток, виконання негайно зупиняється і продовжується в catch{}блоці. Це означає, що якщо ви розмістите виклики бази даних у тому самому try{}блоці та $tableAresults = $dbHandler->doSomethingWithTableA();видасте виняток, $tableBresults = $dbHandler->doSomethingElseWithTableB();не відбудеться. З вашим другим варіантом $tableBresults = $dbHandler->doSomethingElseWithTableB();все одно буде, оскільки це післяcatch{} блоку, коли виконання відновиться.

Не існує ідеального варіанту для кожної ситуації; якщо ви хочете, щоб друга операція продовжувалась незалежно, тоді ви повинні використовувати два блоки. Якщо прийнятно (або бажано), щоб друга операція не відбулася, тоді слід використовувати лише одну.


1

в одній спробі блоку catch ви можете зробити все, що найкраще - це ловити помилку в іншому блоці catch, якщо ви хочете, щоб вони показували своє власне повідомлення про конкретні помилки.


1
try
{
    $tableAresults = $dbHandler->doSomethingWithTableA();
    if(!tableAresults)
    {
        throw new Exception('Problem with tableAresults');
    }
    $tableBresults = $dbHandler->doSomethingElseWithTableB();
    if(!tableBresults) 
    {
        throw new Exception('Problem with tableBresults');
    }
} catch (Exception $e)
{
    echo $e->getMessage();
}

0

Існує жодна проблема для написання декількох рядків виконання за допомогою одного блоку спроби лову, як показано нижче

try{
install_engine();
install_break();
}
catch(Exception $e){
show_exception($e->getMessage());
}

У той момент, коли будь- яке виключення відбудеться або в функції, install_engineабо install_breakелемент керування буде передано функції catch. Ще одна рекомендація - правильно харчуватися за винятком. Що означає, що замість того, щоб писати die('Message'), доцільно завжди правильно обробляти винятки. Ви можете подумати про використанняdie() функції в обробці помилок, але не в обробці винятків.

Коли вам слід використовувати кілька спроб блоку catch Ви можете подумати про блок спроб catch catch, якщо ви хочете, щоб інший виняток блоку коду відображав інший тип виключення, або ви намагаєтесь викинути будь-який виняток з вашого блоку catch, як показано нижче:

try{
    install_engine();
    install_break();
    }
    catch(Exception $e){
    show_exception($e->getMessage());
    }
try{
install_body();
paint_body();
install_interiour();
}
catch(Exception $e){
throw new exception('Body Makeover faield')
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.