मैं एक PHP घातक (`E_ERROR`) त्रुटि कैसे पकड़ सकता हूं?


557

मैं set_error_handler()अधिकांश PHP त्रुटियों को पकड़ने के लिए उपयोग कर सकता हूं , लेकिन यह घातक ( E_ERROR) त्रुटियों के लिए काम नहीं करता है , जैसे कि एक फ़ंक्शन को कॉल करना जो मौजूद नहीं है। क्या इन त्रुटियों को पकड़ने का एक और तरीका है?

मैं mail()सभी त्रुटियों के लिए कॉल करने का प्रयास कर रहा हूं और PHP 5.2.3 चला रहा हूं।


मैंने PHP में सभी त्रुटियों को पकड़ने के लिए एक पूर्ण समाधान के साथ एक विकी-शैली क्यू एंड ए लिखा; जिसे स्टैक ओवरफ्लो पर देखा जा सकता है । समाधान में पांच विधियाँ शामिल हैं जो सभी त्रुटियों को लपेटती हैं जो PHP उत्पन्न कर सकती हैं जो अंततः 'एररहैंडलर' टाइप की गई वस्तु तक त्रुटियों को पारित करेंगी।
DigitalJedi805

इन्हें भी देखें: stackoverflow.com/questions/1087365/…
dreftymac

यह भी देखें: bugs.php.net/bug.php?id=41418
dreftymac

इन्हें भी देखें: stackoverflow.com/questions/7116995
dreftymac

जवाबों:


635

लॉग इन त्रुटियों का उपयोग करते हुए register_shutdown_function, जिसे PHP 5.2+ की आवश्यकता है:

register_shutdown_function( "fatal_handler" );

function fatal_handler() {
    $errfile = "unknown file";
    $errstr  = "shutdown";
    $errno   = E_CORE_ERROR;
    $errline = 0;

    $error = error_get_last();

    if($error !== NULL) {
        $errno   = $error["type"];
        $errfile = $error["file"];
        $errline = $error["line"];
        $errstr  = $error["message"];

        error_mail(format_error( $errno, $errstr, $errfile, $errline));
    }
}

आपको कार्यों error_mailऔर format_errorकार्यों को परिभाषित करना होगा । उदाहरण के लिए:

function format_error( $errno, $errstr, $errfile, $errline ) {
    $trace = print_r( debug_backtrace( false ), true );

    $content = "
    <table>
        <thead><th>Item</th><th>Description</th></thead>
        <tbody>
            <tr>
                <th>Error</th>
                <td><pre>$errstr</pre></td>
            </tr>
            <tr>
                <th>Errno</th>
                <td><pre>$errno</pre></td>
            </tr>
            <tr>
                <th>File</th>
                <td>$errfile</td>
            </tr>
            <tr>
                <th>Line</th>
                <td>$errline</td>
            </tr>
            <tr>
                <th>Trace</th>
                <td><pre>$trace</pre></td>
            </tr>
        </tbody>
    </table>";
    return $content;
}

फ़ंक्शन लिखने के लिए स्विफ्ट मेलर का उपयोग करें error_mail

यह सभी देखें:


113
+1 यह वास्तविक सही उत्तर है। मुझे नहीं पता कि लोगों को "आप घातक त्रुटियों से उबर नहीं सकते" पर सवाल क्यों उठाया जा रहा है - इस सवाल ने कुछ भी ठीक होने के बारे में नहीं कहा।
डेविड हार्कनेस 21

21
धन्यवाद, अच्छा। घातक त्रुटियों (उदाहरण के लिए मेमोरी सीमा) से पुनर्प्राप्त करना कुछ ऐसा नहीं है जो मैं करने की कोशिश करूंगा, लेकिन इन त्रुटियों को खोज योग्य बनाने (ग्राहक को समर्थन टिकट जमा किए बिना) बनाने से सभी फर्क पड़ता है।
इलिजा

2
मूल मेल का उपयोग करना:mail("myname@myemail.com", "My Site: FATAL ERROR", "Details: " . $errno . ' ' . $errstr . ' ' . $errfile . ' ' . $errline);
एरिक मुइसर

4
@ScottNicol स्लाव V सही है, क्योंकि हर बार स्क्रिप्ट खत्म होने पर शटडाउन फ़ंक्शन को कहा जाता है। जिस तरह से अब कोड लिखा गया है, उसी तरह हर पेज पर एक ईमेल भेजा जाएगा।
नैट

2
नोट: यह 100% सही उत्तर नहीं है। त्रुटियों को अनदेखा करने के लिए @ प्रतीक का उपयोग करने वाली कोई भी जगह अभी भी अंतिम त्रुटि सेट करेगी (ताकि आप त्रुटियों को संभाल सकें)। तो आपकी स्क्रिप्ट बिना किसी समस्या के समाप्त हो जाती है लेकिन register_shutdown_function अभी भी सोचता है कि कोई त्रुटि हुई है। केवल PHP 7 के बाद से उनके पास एक फंक्शन error_clear_last () है।
राही

150

मैं अभी इस समाधान के साथ आया (PHP 5.2.0+):

function shutDownFunction() {
    $error = error_get_last();
     // Fatal error, E_ERROR === 1
    if ($error['type'] === E_ERROR) {
         // Do your stuff
    }
}
register_shutdown_function('shutDownFunction');

अलग-अलग त्रुटि प्रकारों को पूर्वनिर्धारित स्थिरांक पर परिभाषित किया जाता है ।


25
यह समाधान मेरे लिए टॉप रेटेड उत्तर की तुलना में बहुत अधिक है। शीर्ष-रेटेड उत्तर आपको हर बार एक स्क्रिप्ट भेजेगा, भले ही कोई त्रुटि न हो। यह एक सख्त गलती पर चलता है।
kmoney12

@periklis, यदि पिछली त्रुटि पहले से ही संभाल ली गई थी, तो error_get_last अभी भी वापस आ जाएगी?
पचेरियर

@ स्पेसर मुझे यकीन नहीं है कि आप "संभाले" के साथ क्या मतलब है, क्योंकि त्रुटियां अपवाद नहीं हैं, लेकिन मुझे लगता है कि उत्तर "हां" है
पेरिक्लिस

3
@Pacerier मैं देखता हूं, यह एक दिलचस्प सवाल है। Php.net/error_get_last पर एक नज़र डालें , टिप्पणियों में से एक का उल्लेख है कि " If an error handler (see set_error_handler ) successfully handles an error then that error will not be reported by this function."
पेरिक्लिस

1
शायद यह स्पष्ट है, कॉलिंग register_shutdown_function()किसी भी घातक त्रुटि से पहले होनी चाहिए। use_1T_memory(); /* memory exhausted error here! */ register_shutdown_function('shutDownFunction');उम्मीद के मुताबिक काम नहीं होगा।
नोबू

117

PHP घातक त्रुटियों से पकड़ने और पुनर्प्राप्त करने के लिए पारंपरिक साधन प्रदान नहीं करता है। ऐसा इसलिए है क्योंकि आम तौर पर एक घातक त्रुटि के बाद प्रसंस्करण को पुनर्प्राप्त नहीं किया जाना चाहिए। एक आउटपुट बफर से मेल खाते स्ट्रिंग (मूल पोस्ट द्वारा बताई गई तकनीक PHP.net पर वर्णित तकनीक) निश्चित रूप से बीमार है। यह बस अविश्वसनीय है।

एक त्रुटि हैंडलर विधि के भीतर से मेल () फ़ंक्शन को कॉल करना समस्याग्रस्त साबित होता है। यदि आपके पास बहुत सी त्रुटियां थीं, तो आपका मेल सर्वर काम के साथ लोड हो जाएगा, और आप अपने आप को एक गर्न इनबॉक्स के साथ पा सकते हैं। इससे बचने के लिए, आप समय-समय पर त्रुटि लॉग को स्कैन करने और तदनुसार सूचनाएं भेजने के लिए क्रोन चलाने पर विचार कर सकते हैं। आप सिस्टम मॉनिटरिंग सॉफ्टवेयर जैसे कि नागियोस को भी देखना पसंद कर सकते हैं ।


शटडाउन फ़ंक्शन को पंजीकृत करने के बारे में बिट से बात करने के लिए:

यह सच है कि आप शटडाउन फ़ंक्शन को पंजीकृत कर सकते हैं, और यह एक अच्छा जवाब है।

यहाँ मुद्दा यह है कि हम आम तौर पर घातक त्रुटियों से उबरने का प्रयास नहीं करना चाहिए, विशेष रूप से अपने आउटपुट बफर के खिलाफ एक नियमित अभिव्यक्ति का उपयोग करके नहीं। मैं स्वीकार किए गए जवाब का जवाब दे रहा था , जो php.net पर एक सुझाव से जुड़ा हुआ है जिसे बाद में बदल दिया गया है या हटा दिया गया है।

यह सुझाव अपवाद हैंडलिंग के दौरान आउटपुट बफर के खिलाफ एक रेगेक्स का उपयोग करने के लिए था, और एक घातक त्रुटि के मामले में (जो भी कॉन्फ़िगर त्रुटि पाठ से आप उम्मीद कर सकते हैं के खिलाफ मिलान द्वारा पता लगाया गया है), किसी प्रकार की वसूली या निरंतर प्रसंस्करण करने का प्रयास करें। यह एक अनुशंसित अभ्यास नहीं होगा (मेरा मानना ​​है कि मैं मूल सुझाव क्यों नहीं पा सकता हूं, मैं भी इसे देख रहा हूं, या php समुदाय ने इसे शूट किया है)।

यह ध्यान देने योग्य हो सकता है कि PHP के अधिक हाल के संस्करणों (5.1 के आसपास) शटडाउन फ़ंक्शन को कॉल करने से पहले लगता है, इससे पहले कि आउटपुट बफ़रिंग कॉल बैक किया जाए। संस्करण 5 और उससे पहले के संस्करण में, यह क्रम उल्टा था (शटडाउन फ़ंक्शन के बाद आउटपुट बफ़रिंग कॉलबैक था)। इसके अलावा, चूंकि 5.0.5 (जो प्रश्नकर्ता के संस्करण 5.2.3 से बहुत पहले है), एक पंजीकृत शटडाउन फ़ंक्शन को कॉल करने से पहले ऑब्जेक्ट को अच्छी तरह से अनलोड किया जाता है, इसलिए आप अपनी इन-मेमोरी ऑब्जेक्ट पर भरोसा नहीं कर पाएंगे कुछ भी।

इसलिए शटडाउन फ़ंक्शन को पंजीकृत करना ठीक है, लेकिन एक शटडाउन फ़ंक्शन द्वारा किए जाने वाले कार्यों का प्रकार संभवतः मुट्ठी भर कोमल शटडाउन प्रक्रियाओं तक सीमित है।

यहां महत्वपूर्ण टेक-ऑफ केवल ज्ञान के कुछ शब्द हैं जो इस प्रश्न पर ठोकर खाते हैं और मूल रूप से स्वीकृत उत्तर में सलाह देखते हैं। अपना आउटपुट बफ़र regex न करें।


25
Pfff, मुझे याद है उन 650.000+ ई-मेल्स के बाद मुझे अगली सुबह मिली। तब से मेरा एररहैंडलर प्रति वेबसर्वर 100 ईमेल पर छाया हुआ है।
बॉब फांगर

14
यह सच नहीं है। आप register_shutdown_function के साथ घातक त्रुटियों को पकड़ सकते हैं।
हिपर्ट्रैकर

56
घातक त्रुटियों को पकड़ने के लिए मौजूद मामलों का उपयोग करना है। उदाहरण के लिए, टेस्ट सूट, बस तब रुकना नहीं चाहिए जब कोई विफल हो जाता है, उन्हें घातक त्रुटि की रिपोर्ट करनी चाहिए और अगले परीक्षण पर जाना चाहिए। PHP सिर्फ बहुत सी चीजों को "घातक" त्रुटी बनाती है।
चाड

24
यह कहते हुए कि वे "पकड़े नहीं जाने चाहिए" बहुत कम देखे गए। एक उत्पादन प्रणाली में, आप की जरूरत है पता करने के लिए जब कुछ विफल रहता है (- डिफ़ॉल्ट php त्रुटि हैंडलिंग बहुत परिष्कृत नहीं है ईमेल सेट या एक डेटाबेस में बातें लॉग इन करें)।
बीटी

8
मैं इस बारे में एक त्वरित टिप्पणी करना चाहता हूं कि आप सभी के बारे में क्या कह रहे हैं "त्रुटियों को पकड़ने की आवश्यकता है, ताकि हम उन्हें ठीक कर सकें" ... Ini निर्देश ini log_errors और error_log।
केली एल्टन

37

खैर, यह संभव है कि घातक त्रुटियों को किसी अन्य तरीके से पकड़ना संभव हो :)

ob_start('fatal_error_handler');

function fatal_error_handler($buffer){
    $error = error_get_last();
    if($error['type'] == 1){
        // Type, message, file, line
        $newBuffer='<html><header><title>Fatal Error </title></header>
                      <style>
                    .error_content{
                        background: ghostwhite;
                        vertical-align: middle;
                        margin:0 auto;
                        padding: 10px;
                        width: 50%;
                     }
                     .error_content label{color: red;font-family: Georgia;font-size: 16pt;font-style: italic;}
                     .error_content ul li{ background: none repeat scroll 0 0 FloralWhite;
                                border: 1px solid AliceBlue;
                                display: block;
                                font-family: monospace;
                                padding: 2%;
                                text-align: left;
                      }
                      </style>
                      <body style="text-align: center;">
                        <div class="error_content">
                             <label >Fatal Error </label>
                             <ul>
                               <li><b>Line</b> ' . $error['line'] . '</li>
                               <li><b>Message</b> ' . $error['message'] . '</li>
                               <li><b>File</b> ' . $error['file'] . '</li>
                             </ul>

                             <a href="javascript:history.back()"> Back </a>
                        </div>
                      </body></html>';

        return $newBuffer;
    }
    return $buffer;
}

3
अगर मैं यह कर सकता हूं तो मैं यह 10 तक बढ़ा दूंगा। यह मेरे लिए उन विषम त्रुटियों पर पूरी तरह से काम करता है जो कभी-कभी तब होती हैं जब कोई पृष्ठ बम होता है और कुछ भी लॉग नहीं किया जा रहा है। मैं लाइव प्रोडक्शन कोड में उपयोग नहीं करूंगा, लेकिन एक पेज पर जोड़ने के लिए बहुत अच्छा है जब असफल होने के लिए एक त्वरित उत्तर की आवश्यकता होती है। धन्यवाद!
नाइट उल्लू

सबसे अच्छा समाधान मैं इंटरनेट पर पाया है में से एक। आकर्षण की तरह काम करता है।
बाउंस

किस तरह से? एक स्पष्टीकरण क्रम में होगा, खासकर यदि यह इंटरनेट पर सबसे अच्छे समाधानों में से एक है (यह और भी बेहतर हो सकता है)।
पीटर मोर्टेंसन

क्या सभी सीएसएस सामग्री की आवश्यकता है? क्या इसे अनिवार्य रूप से नहीं काटा जा सकता है? अपने उत्तर को संपादित करके जवाब दें, यहां टिप्पणियों में नहीं (उचित रूप में)।
पीटर मोर्टेंसन

@PeterMortensen मैं इसका सबसे अच्छा दावा नहीं करता। इसके अलावा समस्या के लिए मेरा व्यक्तिगत समाधान, अन्य बेहतर विकल्प हैं जो बहुत अधिक पेशेवर हैं। जैसा कि किसी ने सुझाव दिया कि इसका उत्पादन अच्छा नहीं है। सीएसएस वहाँ है bcz मैं सिर्फ अपने व्यक्तिगत कोड को काट दिया
sakhunzai

36

घातक त्रुटियां या वसूली योग्य घातक त्रुटियां अब PHP 7 या उच्चतर संस्करणोंError में उदाहरणों को फेंकती हैं । किसी भी अन्य अपवादों की तरह, Errorवस्तुओं को एक try/catchब्लॉक का उपयोग करके पकड़ा जा सकता है ।

उदाहरण:

<?php
$variable = 'not an object';

try {
    $variable->method(); // Throws an Error object in PHP 7 or higger.
} catch (Error $e) {
    // Handle error
    echo $e->getMessage(); // Call to a member function method() on string
}

https://3v4l.org/67vbk

या आप Throwableसभी अपवादों को पकड़ने के लिए इंटरफ़ेस का उपयोग कर सकते हैं ।

उदाहरण:

<?php
    try {
        undefinedFunctionCall();
    } catch (Throwable $e) {
        // Handle error
        echo $e->getMessage(); // Call to undefined function undefinedFunctionCall()
    }

https://3v4l.org/Br0MG

अधिक जानकारी के लिए: http://php.net/manual/en/language.errors.php7.php


2
उपयोग Fatal error: Trait 'FailedTrait' not found inकरते समय किसी त्रुटि को पकड़ने के लिए इसका उपयोग करने के बारे में कोई विचारधारा ReflectionClass?
TCB13

1
@ TCB13 कोशिश करें कि आंतरिक सामग्री को एक फाइल में लपेटें और include "filename.php"इसके बजाय tryब्लॉक में, फिर Throwableकम से कम काम के लिए ब्लॉक को पकड़ें ParseError
निलोक्ट

24

मैंने PHP (लगभग सभी) में सभी त्रुटि प्रकारों को पकड़ने का एक तरीका विकसित किया! मुझे E_CORE_ERROR के बारे में निश्चित नहीं है (मुझे लगता है कि केवल उस त्रुटि के लिए काम नहीं करेगा)! लेकिन, अन्य घातक त्रुटियों के लिए (E_ERROR, E_PARSE, E_COMPILE ...) केवल एक त्रुटि हैंडलर फ़ंक्शन का उपयोग करके ठीक काम करता है! वहाँ मेरा समाधान जाता है:

इस कोड को अपनी मुख्य फ़ाइल (index.php) पर रखें:

<?php
    define('E_FATAL',  E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR |
            E_COMPILE_ERROR | E_RECOVERABLE_ERROR);

    define('ENV', 'dev');

    // Custom error handling vars
    define('DISPLAY_ERRORS', TRUE);
    define('ERROR_REPORTING', E_ALL | E_STRICT);
    define('LOG_ERRORS', TRUE);

    register_shutdown_function('shut');

    set_error_handler('handler');

    // Function to catch no user error handler function errors...
    function shut(){

        $error = error_get_last();

        if($error && ($error['type'] & E_FATAL)){
            handler($error['type'], $error['message'], $error['file'], $error['line']);
        }

    }

    function handler( $errno, $errstr, $errfile, $errline ) {

        switch ($errno){

            case E_ERROR: // 1 //
                $typestr = 'E_ERROR'; break;
            case E_WARNING: // 2 //
                $typestr = 'E_WARNING'; break;
            case E_PARSE: // 4 //
                $typestr = 'E_PARSE'; break;
            case E_NOTICE: // 8 //
                $typestr = 'E_NOTICE'; break;
            case E_CORE_ERROR: // 16 //
                $typestr = 'E_CORE_ERROR'; break;
            case E_CORE_WARNING: // 32 //
                $typestr = 'E_CORE_WARNING'; break;
            case E_COMPILE_ERROR: // 64 //
                $typestr = 'E_COMPILE_ERROR'; break;
            case E_CORE_WARNING: // 128 //
                $typestr = 'E_COMPILE_WARNING'; break;
            case E_USER_ERROR: // 256 //
                $typestr = 'E_USER_ERROR'; break;
            case E_USER_WARNING: // 512 //
                $typestr = 'E_USER_WARNING'; break;
            case E_USER_NOTICE: // 1024 //
                $typestr = 'E_USER_NOTICE'; break;
            case E_STRICT: // 2048 //
                $typestr = 'E_STRICT'; break;
            case E_RECOVERABLE_ERROR: // 4096 //
                $typestr = 'E_RECOVERABLE_ERROR'; break;
            case E_DEPRECATED: // 8192 //
                $typestr = 'E_DEPRECATED'; break;
            case E_USER_DEPRECATED: // 16384 //
                $typestr = 'E_USER_DEPRECATED'; break;
        }

        $message =
            '<b>' . $typestr .
            ': </b>' . $errstr .
            ' in <b>' . $errfile .
            '</b> on line <b>' . $errline .
            '</b><br/>';

        if(($errno & E_FATAL) && ENV === 'production'){

            header('Location: 500.html');
            header('Status: 500 Internal Server Error');

        }

        if(!($errno & ERROR_REPORTING))
            return;

        if(DISPLAY_ERRORS)
            printf('%s', $message);

        //Logging error on php file error log...
        if(LOG_ERRORS)
            error_log(strip_tags($message), 0);
    }

    ob_start();

    @include 'content.php';

    ob_end_flush();
?>

2
लाइन @include 'content.php' क्या करती है?
मार्को

22

आप घातक त्रुटियों को पकड़ / संभाल नहीं सकते हैं, लेकिन आप उन्हें लॉग / रिपोर्ट कर सकते हैं। त्वरित डीबगिंग के लिए मैंने इस सरल कोड में एक उत्तर को संशोधित किया

function __fatalHandler()
{
    $error = error_get_last();

    // Check if it's a core/fatal error, otherwise it's a normal shutdown
    if ($error !== NULL && in_array($error['type'],
        array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING,
              E_COMPILE_ERROR, E_COMPILE_WARNING,E_RECOVERABLE_ERROR))) {

        echo "<pre>fatal error:\n";
        print_r($error);
        echo "</pre>";
        die;
    }
}

register_shutdown_function('__fatalHandler');

लेकिन यह कोड कहां जाएगा?
TKoL

@TKoL पहली पंक्ति। मूल रूप से आपकी स्क्रिप्ट / प्रोग्राम की प्रविष्टि फ़ाइल, इसलिए यह पहले निष्पादित होती है, यदि संभव नहीं है तो इसे एक आम फाइल में
डालें

17

आप इस तरह पंजीकृत शटडाउन फ़ंक्शन के अंदर एक अपवाद नहीं फेंक सकते हैं:

<?php
    function shutdown() {
        if (($error = error_get_last())) {
           ob_clean();
           throw new Exception("fatal error");
        }
    }

    try {
        $x = null;
        $x->method()
    } catch(Exception $e) {
        # This won't work
    }
?>

लेकिन आप दूसरे पेज पर रिक्वेस्ट को कैप्चर और रिडायरेक्ट कर सकते हैं।

<?php
    function shutdown() {
        if (($error = error_get_last())) {
           ob_clean();
           # Report the event, send email, etc.
           header("Location: http://localhost/error-capture");
           # From /error-capture. You can use another
           # redirect, to e.g. the home page
        }
    }
    register_shutdown_function('shutdown');

    $x = null;
    $x->method()
?>

11

यदि आप PHP> = 5.1.0 का उपयोग कर रहे हैं, तो ErrorException वर्ग के साथ ऐसा ही कुछ करें:

<?php
    // Define an error handler
    function exception_error_handler($errno, $errstr, $errfile, $errline ) {
        throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    }

    // Set your error handler
    set_error_handler("exception_error_handler");

    /* Trigger exception */
    try
    {
        // Try to do something like finding the end of the internet
    }
    catch(ErrorException $e)
    {
        // Anything you want to do with $e
    }
?>

9

ज़ेंड फ्रेमवर्क 2 में पाया गया अच्छा समाधान:

/**
 * ErrorHandler that can be used to catch internal PHP errors
 * and convert to an ErrorException instance.
 */
abstract class ErrorHandler
{
    /**
     * Active stack
     *
     * @var array
     */
    protected static $stack = array();

    /**
     * Check if this error handler is active
     *
     * @return bool
     */
    public static function started()
    {
        return (bool) static::getNestedLevel();
    }

    /**
     * Get the current nested level
     *
     * @return int
     */
    public static function getNestedLevel()
    {
        return count(static::$stack);
    }

    /**
     * Starting the error handler
     *
     * @param int $errorLevel
     */
    public static function start($errorLevel = \E_WARNING)
    {
        if (!static::$stack) {
            set_error_handler(array(get_called_class(), 'addError'), $errorLevel);
        }

        static::$stack[] = null;
    }

    /**
     * Stopping the error handler
     *
     * @param  bool $throw Throw the ErrorException if any
     * @return null|ErrorException
     * @throws ErrorException If an error has been catched and $throw is true
     */
    public static function stop($throw = false)
    {
        $errorException = null;

        if (static::$stack) {
            $errorException = array_pop(static::$stack);

            if (!static::$stack) {
                restore_error_handler();
            }

            if ($errorException && $throw) {
                throw $errorException;
            }
        }

        return $errorException;
    }

    /**
     * Stop all active handler
     *
     * @return void
     */
    public static function clean()
    {
        if (static::$stack) {
            restore_error_handler();
        }

        static::$stack = array();
    }

    /**
     * Add an error to the stack
     *
     * @param int    $errno
     * @param string $errstr
     * @param string $errfile
     * @param int    $errline
     * @return void
     */
    public static function addError($errno, $errstr = '', $errfile = '', $errline = 0)
    {
        $stack = & static::$stack[count(static::$stack) - 1];
        $stack = new ErrorException($errstr, 0, $errno, $errfile, $errline, $stack);
    }
}

यह वर्ग आपको ErrorHandlerकभी-कभी विशिष्ट को शुरू करने की अनुमति देता है यदि आपको इसकी आवश्यकता है। और फिर आप हैंडलर को भी रोक सकते हैं।

इस तरह इस वर्ग का उपयोग करें:

ErrorHandler::start(E_WARNING);
$return = call_function_raises_E_WARNING();

if ($innerException = ErrorHandler::stop()) {
    throw new Exception('Special Exception Text', 0, $innerException);
}

// or
ErrorHandler::stop(true); // directly throws an Exception;

पूर्ण वर्ग कोड से लिंक करें:
https://github.com/zendframework/zf2/blob/master/library/Zend/Stdlib/ErrorHandler.php


एक बेहतर उपाय यह है कि मोनोलॉग से एक :

पूर्ण वर्ग कोड से लिंक करें:
https://github.com/Seldaek/monolog/blob/master/src/Monolog/ErrorHandler.php

यह register_shutdown_functionफ़ंक्शन का उपयोग करके FATAL_ERRORS को भी संभाल सकता है । इस वर्ग के अनुसार एक FATAL_ERROR निम्नलिखित में से एक है array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR)

class ErrorHandler
{
    // [...]

    public function registerExceptionHandler($level = null, $callPrevious = true)
    {
        $prev = set_exception_handler(array($this, 'handleException'));
        $this->uncaughtExceptionLevel = $level;
        if ($callPrevious && $prev) {
            $this->previousExceptionHandler = $prev;
        }
    }

    public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1)
    {
        $prev = set_error_handler(array($this, 'handleError'), $errorTypes);
        $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
        if ($callPrevious) {
            $this->previousErrorHandler = $prev ?: true;
        }
    }

    public function registerFatalHandler($level = null, $reservedMemorySize = 20)
    {
        register_shutdown_function(array($this, 'handleFatalError'));

        $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
        $this->fatalLevel = $level;
    }

    // [...]
}

9

मुझे उत्पादन के लिए घातक त्रुटियों को संभालने की आवश्यकता है बजाय इसके कि एक स्टैटिक स्टाइल 503 सर्विस अनुपलब्ध HTML आउटपुट दिखाया जाए । यह निश्चित रूप से "घातक त्रुटियों को पकड़ने" के लिए एक उचित दृष्टिकोण है। यही मैंने किया है:

मेरे पास एक कस्टम एरर हैंडलिंग फंक्शन "error_handler" है जो किसी भी E_ERROR, E_USER_ERROR, आदि पर मेरी "503 सर्विस अनुपलब्ध" HTML पेज प्रदर्शित करेगा। यह अब मेरी घातक त्रुटि को पकड़ने, शटडाउन फ़ंक्शन पर कॉल किया जाएगा।

function fatal_error_handler() {

    if (@is_array($e = @error_get_last())) {
        $code = isset($e['type']) ? $e['type'] : 0;
        $msg = isset($e['message']) ? $e['message'] : '';
        $file = isset($e['file']) ? $e['file'] : '';
        $line = isset($e['line']) ? $e['line'] : '';
        if ($code>0)
            error_handler($code, $msg, $file, $line);
    }
}
set_error_handler("error_handler");
register_shutdown_function('fatal_error_handler');

मेरे कस्टम error_handler फ़ंक्शन में, यदि त्रुटि E_ERROR, E_USER_ERROR, आदि है, तो मैं @ob_end_clean();बफर को खाली करने के लिए भी कहता हूं , इस प्रकार PHP के "घातक त्रुटि" संदेश को हटा देता हूं ।

कड़े इस्सेट () चेकिंग और @साइलेंसिंग फंक्शन का महत्वपूर्ण ध्यान रखें क्योंकि हम नहीं चाहते कि हमारी एरर_हैंडलर स्क्रिप्ट किसी भी तरह की एरर उत्पन्न करे।

अभी भी केप्रो से सहमत होने में, घातक त्रुटियों को पकड़ना "FATAL त्रुटि" के उद्देश्य को पराजित करता है, इसलिए यह वास्तव में आपके लिए आगे की प्रक्रिया करने का इरादा नहीं है। इस शटडाउन प्रक्रिया में कोई भी मेल () फ़ंक्शन न चलाएं क्योंकि आप निश्चित रूप से मेल सर्वर या अपने इनबॉक्स का बैकअप लेंगे। बल्कि इन एरर को फाइल करने के लिए लॉग इन करें और इन एरर को खोजने के लिए क्रोन जॉब शेड्यूल करें। फाइल्स को फाइल करें और उन्हें एडमिन को मेल करें।


7

PHP में बड़ी घातक त्रुटियां हैं। उन्हें E_RECOVERABLE_ERROR के रूप में परिभाषित किया गया है। PHP मैनुअल में E_RECOVERABLE_ERROR का वर्णन है:

घातक त्रुटि। यह इंगित करता है कि संभवतः खतरनाक त्रुटि हुई, लेकिन इंजन को अस्थिर स्थिति में नहीं छोड़ा। यदि उपयोगकर्ता द्वारा परिभाषित हैंडल द्वारा त्रुटि नहीं पकड़ी जाती है (यह भी देखें set_error_handler () ), तो यह एक E_ERROR के रूप में लागू होता है।

आप set_error_handler () का उपयोग करके और E_RECOVERABLE_ERROR की जाँच करके इन "घातक" त्रुटियों को "पकड़" सकते हैं । मुझे यह अपवाद पकड़ने के लिए उपयोगी लगता है जब यह त्रुटि पकड़ी जाती है, तो आप कोशिश / पकड़ का उपयोग कर सकते हैं।

यह प्रश्न और उत्तर एक उपयोगी उदाहरण प्रदान करता है: मैं PHP टाइप हिंटिंग पर "कैटलेबल फेटल एरर" कैसे पकड़ सकता हूं?

E_ERROR त्रुटियां, हालांकि नियंत्रित की जा सकती हैं, लेकिन इंजन के अस्थिर अवस्था में होने के कारण इसे पुनर्प्राप्त नहीं किया जा सकता है।


6

वर्तमान त्रुटि_हैंडलर विधि = पाने के लिए यहां एक अच्छी चाल है)

<?php
    register_shutdown_function('__fatalHandler');

    function __fatalHandler()
    {
        $error = error_get_last();

        // Check if it's a core/fatal error. Otherwise, it's a normal shutdown
        if($error !== NULL && $error['type'] === E_ERROR) {

            // It is a bit hackish, but the set_exception_handler
            // will return the old handler
            function fakeHandler() { }

            $handler = set_exception_handler('fakeHandler');
            restore_exception_handler();
            if($handler !== null) {
                call_user_func(
                    $handler,
                    new ErrorException(
                        $error['message'],
                        $error['type'],
                        0,
                        $error['file'],
                        $error['line']));
            }
            exit;
        }
    }
?>

इसके अलावा मैं यह नोट करना चाहता हूं कि यदि आप कॉल करते हैं

<?php
    ini_set('display_errors', false);
?>

PHP त्रुटि को प्रदर्शित करना बंद कर देती है। अन्यथा, त्रुटि पाठ क्लाइंट को आपकी त्रुटि हैंडलर से पहले भेजा जाएगा।


1
लाइन ini_set ('display_errors', false) के कारण इसे अपग्रेड किया गया;
साहिब खान

यदि किसी कारण से यह बिट पर है, तो यह अभी भी php त्रुटियों को प्रदर्शित करेगा, भले ही आप इसे अलग तरीके से संभालते हों
साहिब खान

5

चूँकि यहाँ अधिकांश उत्तर अनावश्यक रूप से क्रियात्मक हैं, इसलिए यहाँ शीर्ष मतदान के मेरे गैर-कुरूप संस्करण हैं:

function errorHandler($errno, $errstr, $errfile = '', $errline = 0, $errcontext = array()) {
    //Do stuff: mail, log, etc
}

function fatalHandler() {
    $error = error_get_last();
    if($error) errorHandler($error["type"], $error["message"], $error["file"], $error["line"]);
}

set_error_handler("errorHandler")
register_shutdown_function("fatalHandler");

4

ज़रुरी नहीं। घातक त्रुटियों को कहा जाता है, क्योंकि वे घातक हैं। आप उनसे उबर नहीं सकते।


12
पकड़ना और ठीक होना दो अलग-अलग चीजें हैं।
साइमन फोर्सबर्ग

3

मैंने इस फ़ंक्शन को "सैंडबॉक्स" कोड के लिए संभव बनाने के लिए विकसित किया है जो एक घातक त्रुटि का कारण बन सकता है। चूंकि बंद से फेंके गए अपवाद register_shutdown_functionपूर्व-घातक त्रुटि कॉल स्टैक से उत्सर्जित नहीं होते हैं, इसलिए मुझे इस फ़ंक्शन का उपयोग करने का एक समान तरीका प्रदान करने के लिए बाहर निकलने के लिए मजबूर किया जाता है।

function superTryCatchFinallyAndExit( Closure $try, Closure $catch = NULL, Closure $finally )
{
    $finished = FALSE;
    register_shutdown_function( function() use ( &$finished, $catch, $finally ) {
        if( ! $finished ) {
            $finished = TRUE;
            print "EXPLODE!".PHP_EOL;
            if( $catch ) {
                superTryCatchFinallyAndExit( function() use ( $catch ) {
                    $catch( new Exception( "Fatal Error!!!" ) );
                }, NULL, $finally );                
            } else {
                $finally();                
            }
        }
    } );
    try {
        $try();
    } catch( Exception $e ) {
        if( $catch ) {
            try {
                $catch( $e );
            } catch( Exception $e ) {}
        }
    }
    $finished = TRUE;
    $finally();
    exit();
}

3

ऐसी कुछ परिस्थितियाँ हैं, जिनमें भी घातक त्रुटियों को पकड़ा जाना चाहिए (आपको शालीनतापूर्वक बाहर निकलने से पहले कुछ साफ करने की आवश्यकता हो सकती है और बस मरना नहीं है)।

मैंने अपने CodeIgniter अनुप्रयोगों में एक pre_system हुक लागू किया है ताकि मैं ईमेल के माध्यम से अपनी घातक त्रुटियां प्राप्त कर सकूं , और इससे मुझे उन बगों को खोजने में मदद मिली जो रिपोर्ट नहीं किए गए थे (या उन्हें तय किए जाने के बाद रिपोर्ट किए गए थे, जैसा कि मैं पहले से ही उनके बारे में जानता था :))।

Sendemail जाँच करता है कि क्या त्रुटि पहले से ही रिपोर्ट की गई है ताकि यह आपको कई बार ज्ञात त्रुटियों से स्पैम न करे।

class PHPFatalError {

    public function setHandler() {
        register_shutdown_function('handleShutdown');
    }
}

function handleShutdown() {
    if (($error = error_get_last())) {
        ob_start();
        echo "<pre>";
        var_dump($error);
        echo "</pre>";
        $message = ob_get_clean();
        sendEmail($message);
        ob_start();
        echo '{"status":"error","message":"Internal application error!"}';
        ob_flush();
        exit();
    }
}

"Sendemail" क्या है ? क्या आपका मतलब सेंडमेल है ( अपने जवाब को संपादित करके जवाब दें , टिप्पणियों में यहां नहीं)?
पीटर मोर्टेंसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.