it-swarm-vi.com

Cách chính xác để xử lý ngoại lệ là gì?

Trong lõi Joomla tôi vẫn thấy nhiều cuộc gọi như thế này:

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

Nhưng JError không được chấp nhận kể từ khi phát hành Nền tảng 12.1. Vậy tôi nên sử dụng tiêu chuẩn PHP ngoại lệ như thế nào.

20
Harald Leithner

Như @DmitryRekun đã nói, một cuộc thảo luận tốt là ở đây . Mấu chốt cần xem xét trong tất cả những điều này là loại lỗi nào bạn có?

Có hai loại lỗi:

  1. Có thể phục hồi
  2. Không thể phục hồi.

Sự khác biệt tôi có xu hướng tổng hợp như sau:

Can I still show the page that was requested, even though this error occurred?
  • Vâng? - Có thể phục hồi
  • Không? - Không thể phục hồi

Bây giờ chúng tôi biết những gì chúng ta đang đối phó. Những gì bạn nên làm?

Nếu lỗi không thể phục hồi, bạn muốn chuyển hướng chúng đến trang lỗi thay vì tiếp tục đến trang được yêu cầu . Điều đó đơn giản như sau:

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

Exception là một lớp có hai tham số, tin nhắn và mã. Bạn nên thử sử dụng Mã phản hồi HTTP nếu chúng phù hợp với kịch bản của bạn.

Nếu lỗi có thể phục hồi, có thể bạn chỉ muốn hiển thị thông báo lại cho người dùng cuối trong khi vẫn hiển thị cho họ trang mà họ yêu cầu. Điều này thường có nghĩa là bạn nên 'enqueue' một tin nhắn cho ứng dụng:

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

enqueueMessage nhận hai tham số, thông báo lỗi và loại thông báo. Thêm thông tin tại đây (ở dưới cùng).


Ngoài ra còn có một tình huống thứ ba xảy ra khá thường xuyên đối với tôi ít nhất. Joomla sẽ đưa ra các ngoại lệ cho các lỗi khác nhau (chẳng hạn như lỗi truy vấn cơ sở dữ liệu). Điều này có nghĩa là Joomla nghĩ rằng lỗi này là không thể phục hồi. Tuy nhiên, dù sao bạn cũng có thể muốn tiếp tục. (Ví dụ: nếu tôi thay đổi bảng khi cập nhật tiện ích mở rộng của mình, tôi chỉ có thể chạy truy vấn ALTER, sẽ ném ngoại lệ nếu bảng đã bị thay đổi trước đó.)

Trong trường hợp đó, bạn muốn bọc mã có thể đưa ra một ngoại lệ trong phần thử ... bắt:

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
}

Lưu ý rằng những gì bạn đang làm là "bắt" lỗi không thể phục hồi và buộc hệ thống khôi phục và tiếp tục hiển thị trang được yêu cầu.


Thêm tất cả điều này và trường hợp của bạn sẽ là một lỗi không thể phục hồi. (Tôi biết điều này bởi vì bạn đã 'trả về false' sau đó, vì vậy bạn có thể không có kế hoạch tiếp tục và đang từ bỏ chức năng.)

Vì vậy, tôi sẽ viết lại điều này như sau:

// 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.
}
17
David Fritsch

Đây là cách tôi quản lý một lỗi.

Xem hoặc Trình điều khiển

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

Vì vậy, nếu tôi nhận được mã 404 từ Mô hình của tôi (ví dụ):

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

Sau đó, tôi bắt nó trong chế độ xem hoặc trình điều khiển và ném thêm một Ngoại lệ mà Joomla sẽ xử lý và sẽ hiển thị trang 404. Đối với bất kỳ khác, tôi chỉ hiển thị một số thông báo lỗi chung cho người dùng.

Ngoài ra đọc cuộc thảo luận thú vị này về xử lý lỗi.

12
Dmitry Rekun

Hầu hết các khối mã như thế này có thể được thay thế đơn giản bằng enqueueMessage vì chúng không thực sự gây ra lỗi và chỉ cần sử dụng JError để in chúng ra.

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