Jaki jest właściwy sposób obsługi wyjątków?

20

W jądrze Joomla wciąż znajduję wiele takich połączeń:

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

Jednak JError jest przestarzały od wydania platformy 12.1. Jak powinienem używać standardowych wyjątków PHP.

Harald Leithner
źródło
1
Różnica między przejściem z JError a błędami PHP to nie tylko proces jednego kliknięcia. Więc jeśli jesteś pewien, że dostaniesz wyjątek, wykonaj instrukcję try / catch jak w odpowiedzi poniżej. Jeśli jesteś pewien, że dostaniesz JError, musisz zrobić kod podobny do powyższego :)
George Wilson

Odpowiedzi:

17

Jak powiedział @DmitryRekun, dobra dyskusja jest tutaj . Kluczową kwestią do rozważenia w tym wszystkim jest to, jaki rodzaj błędu masz?

Istnieją dwa rodzaje błędów:

  1. Do odzyskania
  2. Nie do odzyskania.

Różnicę podsumowuję następująco:

Can I still show the page that was requested, even though this error occurred?
  • Tak? - Do odzyskania
  • Nie? - Nie do odzyskania

Teraz, gdy wiemy, z czym mamy do czynienia. Co powinieneś zrobić?

Jeśli błędu nie można naprawić, należy przekierować go na stronę błędu zamiast kontynuować na żądanej stronie . Jest to tak proste, jak następujące:

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

Exceptionto klasa, która przyjmuje dwa parametry, komunikat i kod. Zaleca się, aby spróbować użyć kodów odpowiedzi HTTP, jeśli pasują one do Twojego scenariusza.

Jeśli błąd można naprawić, prawdopodobnie po prostu chcesz wyświetlić komunikat użytkownikowi końcowemu, wciąż pokazując mu żądaną stronę. Zazwyczaj oznacza to, że należy „kolejkować” komunikat dla aplikacji:

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

enqueueMessageprzyjmuje dwa parametry, komunikat o błędzie i typ komunikatu. Więcej informacji tutaj (na dole).


Jest też trzecia sytuacja, która przynajmniej dla mnie zdarza się dość często. Joomla zgłosi wyjątki dla różnych błędów (takich jak błąd zapytania do bazy danych). Oznacza to, że Joomla uważa, że ​​tego błędu nie da się naprawić. Mimo to możesz kontynuować. (Na przykład, jeśli zmieniam tabelę po aktualizacji mojego rozszerzenia, mogę po prostu uruchomić ALTERzapytanie, które spowoduje wyjątek, jeśli tabela została wcześniej zmieniona).

W takim przypadku chcesz owinąć kod, który może zgłosić wyjątek w sekcji try ... 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
}

Pamiętaj, że to, co robisz, polega na „wychwyceniu” nieodwracalnego błędu i zmuszeniu systemu do odzyskania i kontynuowania wyświetlania żądanej strony.


Dodaj to wszystko, a twoja sprawa powinna być nieodwracalnym błędem. (Wiem o tym, ponieważ potem „zwracasz fałsz”, więc prawdopodobnie nie planujesz kontynuować i rezygnujesz z funkcji).

Dlatego przepisałbym to w następujący sposób:

// 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.
}
David Fritsch
źródło
Dobra odpowiedź! Ale nie polegałbym, $this->get('Errors')ponieważ jest on również przestarzały.
Dmitry Rekun,
Wszelkie uwagi na temat nieudanych twierdzeń, czyli błędów wewnętrznych? Chciałbym, aby program umarł natychmiast po nieudanym stwierdzeniu - czy istnieje sposób specyficzny dla Joomla? W tej chwili rejestruję program obsługi aser, jeśli JDEBUGjest true.
Olle Härstedt,
12

Oto jak zarządzam błędami.

Widok lub kontroler

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');
}

Więc jeśli otrzymam kod 404 z mojego modelu (na przykład):

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

Następnie łapię to w widoku lub kontrolerze i rzucam jeszcze jeden wyjątek, który Joomla obsłuży i wyświetli stronę 404. W przypadku każdego innego po prostu pokazuję użytkownikowi ogólny komunikat o błędzie.

Przeczytaj także tę interesującą dyskusję na temat obsługi błędów.

Dmitry Rekun
źródło
4

Większość takich bloków kodu można po prostu zastąpić, enqueueMessageponieważ tak naprawdę nie działają one na błąd i po prostu JErrordrukują je.

// Check for errors.
if (count($errors = $this->get('Errors'))) {
    foreach($errors as $error) {
        JFactory::getApplication()->enqueueMessage($error, 'error');
    }
}
Spunkie
źródło