Який правильний спосіб поводження з винятками?


20

У ядрі Joomla я знаходжу ще багато таких дзвінків:

    // Check for errors.
    if (count($errors = $this->get('Errors')))
    {
        JError::raiseError(500, implode("\n", $errors));
        return false;
    }

Але JError застарілий з моменту випуску платформи 12.1. Тож як я повинен використовувати стандартні винятки PHP.


1
На відміну від переходу від JError до PHP помилок, на жаль, не є просто одним кліком. Тож якщо ви впевнені, що збираєтесь отримати виняток, тоді зробіть заяву спробу / лову, як зазначено у відповіді нижче. Якщо ви впевнені, що збираєтесь отримати JError, тоді вам потрібно зробити аналогічний код вищезгаданому :)
Джордж Вілсон

Відповіді:


17

Як сказав @DmitryRekun, гарне обговорення тут . Ключовим елементом, який слід враховувати у всьому цьому, є тип помилок у вас?

Існує два типи помилок:

  1. Відновлюється
  2. Неможливий

Різницю я, як правило, підсумовую так:

Can I still show the page that was requested, even though this error occurred?
  • Так? - Відновлювані
  • Ні? - Невідшкодований

Тепер, коли ми знаємо, з чим маємо справу. Що тобі слід робити?

Якщо помилку неможливо усунути, ви хочете перенаправити їх на сторінку помилок, а не продовжувати переглядати потрібну сторінку . Це так просто, як наступне:

throw new Exception(JText::_('COM_MYCOMP_ERROR_MESSAGE_NOT_FOUND'), 404);

Exceptionце клас, який приймає два параметри, повідомлення та код. Рекомендується спробувати використовувати коди відповідей HTTP, якщо вони відповідають вашому сценарію.

Якщо помилку можна виправити, ви, ймовірно, просто захочете відобразити повідомлення кінцевому користувачеві, продовжуючи показувати їм потрібну сторінку. Зазвичай це означає, що вам слід "запхнути" повідомлення для програми:

JFactory::getApplication()->enqueueMessage($error, 'error');

enqueueMessageприймає два параметри, повідомлення про помилку та тип повідомлення. Більше інформації тут (внизу).


Є також третя ситуація, яка трапляється досить часто для мене, принаймні. Joomla викине винятки за різні помилки (наприклад, помилка запиту бази даних). Це означає, що Джомла вважає, що цю помилку не можна виправити. Однак ви можете продовжити все-таки. (Наприклад, якщо я змінюю таблицю під час оновлення свого розширення, я можу просто запустити ALTERзапит, який видасть виняток, якщо таблиця була раніше змінена.)

У такому випадку ви хочете обернути код, який може кинути виняток у розділі спробувати ... catch:

try {
    // exception generating code
    throw new Exception('Normally you would have other code that calls a class that throws the exception', 500);
} catch (Exception $e) {
    $msg = $e->getMessage(); // Returns "Normally you would have other code...
    $code = $e->getCode(); // Returns '500';
    JFactory::getApplication()->enqueueMessage($msg, 'error'); // commonly to still display that error
}

Зауважте, що ви робите "ловити" непоправну помилку і змушувати систему відновитись і продовжувати показувати запитувану сторінку.


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

Таким чином я би переписав це так:

// Check for errors.
if (count($errors = $this->get('Errors')))
{
    throw new Exception(implode("\n", $errors), 500);
    return false; // you can remove this too, technically since the exception will take you out of this function.
}

Гарна відповідь! Але я б не покладався на $this->get('Errors')це, оскільки це також застаріло.
Дмитро Рекун

Будь-які коментарі до невдалих тверджень, тобто внутрішніх помилок? Я хотів би, щоб програма негайно померла при невдалому твердженні - чи існує специфічний для Joomla спосіб це зробити? На даний момент я реєструю оброблювач затвердження, якщо JDEBUGє true.
Olle Härstedt

12

Ось як я керую помилками.

Перегляд або контролер

try
{
    $this->item = $this->get('Item');
}
catch (Exception $e)
{
    if ($e->getCode() == 404)
    {
        // Not found
        throw new Exception($e->getMessage(), 404);
    }

    // Generic errors
    JFactory::getApplication()->enqueueMessage(JText::_('COM_MYCOMP_ERROR_OCCURRED'), 'error');
}

Тож якщо я отримаю код 404 від Моєї моделі (наприклад):

if (empty($data))
{
    throw new Exception(JText::_('COM_MYCOMP_ERROR_MESSAGE_NOT_FOUND'), 404);
}

Потім я перехоплюю його у вигляд або контролер і кидаю ще один Виняток, який Joomla впорається, і відобразить сторінку 404. Для будь-якого іншого я просто показую користувачеві якесь загальне повідомлення про помилку.

Також прочитайте цю цікаву дискусію про обробки помилок.


4

Більшість подібних блоків коду можна просто замінити, enqueueMessageоскільки вони насправді не діють на помилку, а просто використовуються JErrorдля їх роздрукування.

// Check for errors.
if (count($errors = $this->get('Errors'))) {
    foreach($errors as $error) {
        JFactory::getApplication()->enqueueMessage($error, 'error');
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.