捕获PHP / CodeIgniter中的意外终止

时间:2013-02-26 03:13:15

标签: php api codeigniter rest

我正在使用CodeIgniter来托管RESTful API,我想捕获任何未返回预期状态代码的API响应。这可能是最容易用一个例子解释的。通常,我的代码如下所示:

function post_comment()
{
     $comment = $_POST['comment'];
     $result = do_something_with_comment($comment);

     if ($result === true)
     {
         return_json_response(200, 'OK!');
     }
     else
     {
         return_json_response(400, 'Something terrible happened...');
     }
}

返回200或400是完全有效的。我的问题是:当do_something_with_comment()有致命错误时,或者如果我在do_something_with_comment()中留下打印调试时,如何捕获错误。在前一种情况下,我永远不会达到return_json_response()。在后一种情况下,我会到达它,但屏幕调试将破坏JSON响应。

有没有办法在此周围创建一个通用的包装器来捕获任何意外的输出或终止?

2 个答案:

答案 0 :(得分:2)

一般情况下你可以:

尽可能使用异常/异常处理

注册一个将PHP错误转换为异常的自定义错误处理程序,例如将它放在config / config.php的顶部

function my_error_handler($errno, $errstr, $errfile, $errline)
{
    if (!(error_reporting() & $errno))
    {
        // This error code is not included in error_reporting
        return;
    }
    log_message('error', "$errstr @$errfile::$errline($errno)" );
    throw new ErrorException( $errstr, $errno, 0, $errfile, $errline );
}
set_error_handler("my_error_handler");

注册未捕获的异常处理程序,在config / config.php

中输入类似的内容
function my_exception_handler($exception)
{
    echo '<pre>';
    print_r($exception);
    echo '</pre>';
    header( "HTTP/1.0 500 Internal Server Error" );
}
set_exception_handler("my_exception_handler");

修改

设置终止处理程序:

function my_fatal_handler()
{
    $errfile = "unknown file";
    $errstr  = "Fatal error";
    $errno   = E_CORE_ERROR;
    $errline = 0;
    $error = error_get_last();
    if ( $error !== NULL )
    {
        echo '<pre>';
        print_r($error);
        echo '</pre>';
        header( "HTTP/1.0 500 Internal Server Error" );
    }
}
register_shutdown_function("my_fatal_handler");

设置一个自定义断言处理程序,将断言转换为异常,在config / config.php中输入类似的内容:

function my_assert_handler($file, $line, $code)
{
    log_message('debug', "assertion failed @$file::$line($code)" );
    throw new Exception( "assertion failed @$file::$line($code)" );
}
assert_options(ASSERT_ACTIVE,     1);
assert_options(ASSERT_WARNING,    0);
assert_options(ASSERT_BAIL,       0);
assert_options(ASSERT_QUIET_EVAL, 0);
assert_options(ASSERT_CALLBACK, 'my_assert_handler');

然后,这是你的答案,在你的控制器中使用这样的包装器

public function controller_method( )
{
    try
    {
        // normal flow
    }
    catch( Exception $e )
    {
        log_message( 'error', $e->getMessage( ) . ' in ' . $e->getFile() . ':' . $e->getLine() );
        // on error
    }
}

您可以根据自己的喜好调整和自定义整个内容!

希望这有帮助。

修改

您还需要拦截CI show_error方法。将其放在application / core / MY_exceptions.php中:

class MY_Exceptions extends CI_Exceptions
{
    function show_error($heading, $message, $template = 'error_general', $status_code = 500)
    {
        log_message( 'debug', print_r( $message, TRUE ) );
        throw new Exception(is_array($message) ? $message[1] : $message, $status_code );
    }
}

并在application / config / database.php中将此设置保留为FALSE,以将数据库错误转换为异常。

$db['default']['db_debug'] = TRUE;

CI有一些(非常)弱点,例如异常处理,但这将在很大程度上纠正这一点。

答案 1 :(得分:1)

有一个函数register_shutdown_function(),您可以在其中为每个脚本设置自己的结束处理程序。在那里做你需要的。

BTW:尽可能使你的脚本成为防弹。您的脚本不应该有致命错误,段错误或此类运行时错误。对客户端无效的任何响应在请求处理的上下文中都是有效的。我建议你看一下Symfony2框架,或者简单地看看它的HttpKernel / HttpFoundation组件,因为它们很好地将这个过程包装在友好的界面中。