1

我正在使用 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 响应。

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

4

2 回答 2

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 有一些(非常)弱点,例如异常处理,但这将大大有助于纠正这一点。

于 2013-02-26T09:48:27.620 回答
1

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

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

于 2013-02-26T03:15:18.473 回答