سؤال

هذا مكتوب بلغة PHP، لكنه في الواقع لا يعرف اللغة.

try
{
    try
    {
        $issue = new DM_Issue($core->db->escape_string($_GET['issue']));
    }
    catch(DM_Exception $e)
    {
        throw new Error_Page($tpl, ERR_NOT_FOUND, $e->getMessage());
    }
}
catch(Error_Page $e)
{
    die($e);
}

هل تعتبر المحاولة المتداخلة والتقاط الكتل ممارسة جيدة يجب اتباعها؟يبدو الأمر ضخمًا بعض الشيء بالنسبة لصفحة الخطأ فقط - ولكن مدير بيانات المشكلة الخاص بي يطرح استثناءً في حالة حدوث خطأ وأعتبر ذلك طريقة جيدة لاكتشاف الخطأ.

استثناء Error_Page هو ببساطة مترجم لصفحة الخطأ.

قد أكون متحذلقًا فحسب، لكن هل تعتقد أن هذه طريقة جيدة للإبلاغ عن الأخطاء، وإذا كان الأمر كذلك، فهل يمكنك اقتراح طريقة أفضل لكتابة هذا؟

شكرًا

هل كانت مفيدة؟

المحلول

أنت تستخدم استثناءات لمنطق الصفحة، وأنا شخصياً أعتقد أن هذا ليس بالأمر الجيد.يجب استخدام الاستثناءات للإشارة إلى حدوث أشياء سيئة أو غير متوقعة، وليس للتحكم في إخراج صفحة الخطأ.إذا كنت تريد إنشاء صفحة خطأ بناءً على الاستثناءات، ففكر في استخدام set_exception_handler.يتم تشغيل أي استثناءات لم يتم اكتشافها من خلال أي طريقة رد اتصال تحددها.ضع في اعتبارك أن هذا لا يوقف "فتاكة" الاستثناء.بعد تمرير الاستثناء من خلال رد الاتصال الخاص بك، سيتوقف التنفيذ كالمعتاد بعد أي استثناء لم يتم اكتشافه.

نصائح أخرى

أعتقد أنه من الأفضل ألا تعشش.إذا كنت تتوقع أنواعًا متعددة من الاستثناءات، فاحصل على العديد من عمليات الصيد.

try{
  Something();
}
catch( SpecificException se )
{blah();}
catch( AnotherException ae )
{blah();}

والوضع المثالي هو أن يتم اكتشاف الاستثناءات عند المستوى الذي يمكنه التعامل معها.ليس قبل (مضيعة للوقت)، وليس بعد (فقدان السياق).

لذا، إذا كان $tpl وERR_NOT_FOUND عبارة عن معلومات "معروفة" فقط بالقرب من استدعاء DM_Issue الجديد، على سبيل المثال، نظرًا لوجود أماكن أخرى تقوم فيها بإنشاء DM_Issue وتريد ERR_SOMETHING_ELSE، أو لأن قيمة $tpl تختلف، فأنت 'إعادة التقاط الاستثناء الأول في المكان الصحيح.

أما كيفية الوصول من ذلك المكان إلى الموت فهو سؤال آخر.والبديل هو أن يموت هناك.ولكن إذا قمت بذلك، فلن تكون هناك فرصة لتدخل التعليمات البرمجية لفعل أي شيء (مثل مسح شيء ما بطريقة ما أو تعديل صفحة الخطأ) بعد الخطأ ولكن قبل الخروج.من الجيد أيضًا أن يكون لديك تدفق تحكم واضح.لذلك أعتقد أنك جيد.

أفترض أن المثال الخاص بك ليس تطبيقًا كاملاً - إذا كان كذلك، فمن المحتمل أن يكون مطولًا بلا داعٍ، ويمكن أن تموت في جملة الصيد DM_Exception.لكن بالنسبة للتطبيق الحقيقي، فأنا أوافق على مبدأ عدم الموت في مكان مجهول.

اعتمادًا على احتياجاتك، قد يكون هذا أمرًا جيدًا، لكنني متردد بشكل عام في التقاط استثناء، ولف الرسالة في استثناء جديد، وإعادة طرحها لأنك تفقد معلومات تتبع المكدس (وربما معلومات أخرى) من الاستثناء الأصلي في التغليف استثناء.إذا كنت بالتأكيد أنك لا تحتاج إلى هذه المعلومات عند فحص استثناء الالتفاف، فمن المحتمل أن يكون الأمر على ما يرام.

لست متأكدًا من PHP ولكن على سبيل المثال.في C#، يمكنك الحصول على أكثر من كتلة التقاط واحدة، لذا ليست هناك حاجة لمجموعات محاولة/التقاط متداخلة.

بشكل عام، أعتقد أن التعامل مع الأخطاء باستخدام حاول/قبض/أخيرًا هو دائمًا أمر منطقي، وأيضًا لإظهار صفحة خطأ "فقط".إنها طريقة نظيفة للتعامل مع الأخطاء وتجنب السلوك الغريب عند التعطل.

لن أطرح استثناءً بشأن المشكلة التي لم يتم العثور عليها - إنها حالة صالحة للتطبيق، ولا تحتاج إلى تتبع المكدس فقط لعرض 404.

ما تحتاج إلى اكتشافه هو حالات الفشل غير المتوقعة، مثل أخطاء SQL - وذلك عندما تكون معالجة الاستثناءات مفيدة.سأقوم بتغيير الكود الخاص بك ليبدو أكثر مثل هذا:

try {
    $issue = DM_Issue::fetch($core->db->escape_string($_GET['issue']));
}
catch (SQLException $e) {
    log_error('SQL Error: DM_Issue::fetch()', $e->get_message());
}
catch (Exception $e) {
    log_error('Exception: DM_Issue::fetch()', $e->get_message());
}

if(!$issue) {
    display_error_page($tpl, ERR_NOT_FOUND);
}
else
{
    // ... do stuff with $issue object.
}

يجب استخدام الاستثناءات فقط في حالة وجود حدث يحتمل أن يؤدي إلى خرق الموقع - مثل عدم تنفيذ استعلام قاعدة البيانات بشكل صحيح أو تكوين شيء ما بشكل خاطئ.وخير مثال على ذلك هو أن ذاكرة التخزين المؤقت أو دليل السجل غير قابل للكتابة بواسطة عملية Apache.

الفكرة هنا هي أن الاستثناءات مخصصة لك، كمطور، لإيقاف التعليمات البرمجية التي يمكنها تعطيل الموقع بأكمله حتى تتمكن من إصلاحها قبل النشر.إنها أيضًا فحوصات سلامة للتأكد من أنه في حالة تغير البيئة (على سبيل المثال.يقوم شخص ما بتغيير أذونات مجلد ذاكرة التخزين المؤقت أو تغيير نظام قاعدة البيانات) يتم إيقاف الموقع قبل أن يتسبب في إتلاف أي شيء.

لذا، لا؛معالجات الصيد المتداخلة ليست فكرة جيدة.في صفحاتي، يقوم ملف Index.php الخاص بي بتغليف التعليمات البرمجية الخاصة به في كتلة محاولة...ذاكرة التخزين المؤقت - وإذا حدث شيء سيئ، فإنه يتحقق لمعرفة ما إذا كان قيد الإنتاج أم لا؛وإما أن يرسل لي بريدًا إلكترونيًا ويعرض صفحة خطأ عامة، أو يعرض الخطأ مباشرة على الشاشة.

يتذكر:PHP ليس C#.C# هي (باستثناء (hehe، لا يقصد التورية :p) من ASP.net) للتطبيقات التي تحتوي على حالة - في حين أن PHP هي لغة برمجة نصية عديمة الحالة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top