Обработчик исключений PHP убивает скрипт - PullRequest
3 голосов
/ 24 января 2011

в основном у меня есть пользовательский обработчик исключений.Когда я обрабатываю исключение, я просто хочу, чтобы оно повторило сообщение и продолжило сценарий.Но после того, как мой метод обработал исключение, скрипт не продолжает.

Это поведение php или мой обработчик исключений что-то делает неправильно?

Ответы [ 4 ]

3 голосов
/ 24 января 2011

Это поведение php. Это отличается от set_error_handler() тем, что, согласно руководству по set_exception_handler () , Выполнение будет остановлено после вызова обработчика исключения. Поэтому убедитесь, что вы перехватываете все исключения, позволяя только тем, кого хотите уничтожить ваш скрипт.

Именно поэтому set_error_handler() плохо сочетается с исключениями и set_exception_handler() при преобразовании всех ошибок в исключения ... если только вы на самом деле не подразумеваете, что ваше приложение должно быть настолько строго закодировано, что любое уведомление или предупреждение останавливает сценарий. Но, по крайней мере, он дает вам трассировку по этому вызову с использованием неустановленного ключа массива.

2 голосов
/ 24 января 2011

С помощью пользовательского обработчика исключений , вы захотите перехватить исключение в блоке try / catch и выполнить там любую обработку, какую захотите.

Ниже приведен пример из CodeUnit of Craig

try {
    $error = 'Throw this error';
    throw new Exception($error);
    echo 'Never get here';
}
catch (Exception $e)
{
    echo 'Exception caught: ',  $e->getMessage(), "\n";
}

Если вы хотите перехватить и распечатать любое необработанное исключение, вы можете установить обработчик исключений верхнего уровня, такой как этот пример из w3schools (рядом с нижнимстраницы)

<?php
 function myException($exception){
    echo "<b>Exception:</b> " , $exception->getMessage();
 }

 set_exception_handler('myException');

 throw new Exception('Uncaught Exception occurred');
?> 

должно печатать: «Исключение: произошло необученное исключение»

0 голосов
/ 24 июля 2014

Вы можете сделать это:

function handleError($errno, $errstring, $errfile, $errline, $errcontext) {
    if (error_reporting() & $errno) {
        // only process when included in error_reporting
        return processError($errno, $errstring);
    }
    return true;
}

function handleException($exception){
    // Here, you do whatever you want with the generated
    // exceptions. You can store them in a file or database,
    // output them in a debug section of your page or do
    // pretty much anything else with it, as if it's a
    // normal variable
}

function processError($code, $message){
    switch ($code) {
        case E_ERROR:
        case E_CORE_ERROR:
        case E_USER_ERROR:
            // Throw exception and stop execution of script
            throw new Exception($message, $code);
        default:
            // Execute exception handler and continue execution afterwards
            return handleException(new Exception($message, $code));
    }
}

// Set error handler to your custom handler
set_error_handler('handleError');
// Set exception handler to your custom handler
set_exception_handler('handleException');


// ---------------------------------- //

// Generate warning
processError(E_USER_WARNING, 'This went wrong, but we can continue');

// Generate fatal error :
processError(E_USER_ERROR, 'This went horrible wrong');

Альтернативный подход:

function handleError($errno, $errstring, $errfile, $errline, $errcontext) {
    if (error_reporting() & $errno) {
        // only process when included in error_reporting
        return handleException(new \Exception($errstring, $errno));
    }
    return true;
}

function handleException($exception){
    // Here, you do whatever you want with the generated
    // exceptions. You can store them in a file or database,
    // output them in a debug section of your page or do
    // pretty much anything else with it, as if it's a
    // normal variable

    switch ($code) {
        case E_ERROR:
        case E_CORE_ERROR:
        case E_USER_ERROR:
            // Make sure script exits here
            exit(1);
        default:
            // Let script continue
            return true;
    }
}

// Set error handler to your custom handler
set_error_handler('handleError');
// Set exception handler to your custom handler
set_exception_handler('handleException');


// ---------------------------------- //

// Generate warning
trigger_error('This went wrong, but we can continue', E_USER_WARNING);

// Generate fatal error :
trigger_error('This went horrible wrong', E_USER_ERROR);

Преимущество последней стратегии заключается в том, что вы получаете параметр $errcontext, если вы делаете $exception->getTrace() в функции handleException.

Это очень полезно для определенных целей отладки. К сожалению, это работает, только если вы используете trigger_error непосредственно из своего контекста, что означает, что вы не можете использовать функцию / метод-оболочку для псевдонима функции trigger_error (поэтому вы не можете сделать что-то вроде function debug($code, $message) { return trigger_error($message, $code); }, если хотите контекстные данные в вашей трассировке).


EDIT

Я нашел один dirty способ решения проблемы trigger_error.

Рассмотрим следующий код:

define("__DEBUG__", "Use of undefined constant DEBUG - assumed 'DEBUG'");

public static function handleError($code, $message, $file, $line, $context = false) {
    if ($message == __DEBUG__) {
        return static::exception(new \Exception(__DEBUG__, E_USER_WARNING));
    } else {
        if (error_reporting() & $code) {
            return static::exception(new \Exception($message, $code));
        }
        return true;
    }
}

public static function handleException($e) {
    global $debug;
    $code = $e->getCode();
    $trace = $e->getTrace();
    if ($e->getMessage() == __DEBUG__) {
        // DEBUG
        array_push($debug, array(
            '__TIME__' => microtime(),
            '__CONTEXT__' => array(
                'file' => $trace[0]['file'],
                'line' => $trace[0]['line'],
                'function' => $trace[1]['function'],
                'class' => $trace[1]['class'],
                'type' => $trace[1]['type'],
                'args' => $trace[0]['args'][4]
            )
        ));
    } else {
       // NORMAL ERROR HANDLING
    }
    return true;
}

С этим кодом вы можете использовать оператор DEBUG;, чтобы сгенерировать список всех доступных переменных и трассировку стека для любого конкретного контекста. Этот список хранится в глобальной переменной $debug. Вы можете добавить его в файл журнала, добавить в базу данных или распечатать.

Это ОЧЕНЬ, ОЧЕНЬ грязный хак, поэтому используйте его по своему усмотрению. Тем не менее, это может значительно облегчить отладку и позволяет создать чистый интерфейс для вашего кода отладки.

0 голосов
/ 24 января 2011

Посмотрите на следующий код. у меня это сработало:

define(BR, "<br/>");
try {
   echo "throwing exception" . BR;
   throw new Exception("This is exception");
}
catch(Exception $ex) {
    echo "caught exception: " . BR . $ex->getMessage() . BR;

}
echo "Keep on going!. ..." . BR;

печатает следующее:

throwing exception
caught exception: 
This is exception
Keep on going!. ...

Что ты скажешь? Можете ли вы показать код вашего обработчика кода?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...