วิธีที่ถูกต้องสำหรับการจัดการข้อยกเว้นคืออะไร?


20

ใน Joomla core ฉันยังพบการโทรจำนวนมากเช่นนี้:

    // 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 จะโยนข้อยกเว้นสำหรับข้อผิดพลาดที่แตกต่างกัน (เช่นข้อผิดพลาดแบบสอบถามฐานข้อมูล) ซึ่งหมายความว่า 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')เพราะมันเลิกใช้แล้ว
Dmitry Rekun

ความคิดเห็นใด ๆ เกี่ยวกับการยืนยันที่ล้มเหลวนั่นคือข้อผิดพลาดภายใน? ฉันต้องการให้โปรแกรมตายทันทีเมื่อยืนยันล้มเหลว - มีวิธีการเฉพาะ 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');
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.