13

我对列有unique限制。当这段代码运行时,我从框架中得到错误日志,但这不是我在异常块中给出的。
如果存在唯一列,那么我想查询其主键并将其设置为$id并返回页面。现在它停止在 db 错误上,而不是进入Catch block.
这是我的代码:

try {
            $result = $this->db->insert('email', $new_email);
            if ($result)
            {
                $id = $this->db->insert_id();    
            } else {
                throw new Exception("$$$$$$$$$$$$$Log database error");
            }
        } catch (Exception $e) {
            log_message('error',$e->getMessage());
            return;
        }

**Error Messages**我从框架中得到:

DEBUG - 2013-04-07 05:00:38 --> DB Transaction Failure
ERROR - 2013-04-07 05:00:38 --> Query error: Duplicate entry 

我不知道它有什么问题。

4

5 回答 5

31

CI 对异常没有很好的支持。您的数据库查询将调用一些模糊的 CI error_logging 事物,称为 show_error()。您需要做的是设置适当的异常处理。

基本上你可以按照整个食谱。

现在你所有的数据库错误都会自动抛出异常。作为奖励,您可以在整个 CI 应用程序中进行良好的异常处理。

注册一个自定义错误处理程序,将 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 有一些(非常)弱点,例如异常处理,但这将大大有助于纠正这一点。

如果要使用事务,请确保对异常进行回滚。与此相关的从不(如在 EVER 中)使用持久连接作为打开的事务,其他会话特定的数据库状态将被其他会话拾取/继续。

于 2013-04-07T09:10:53.763 回答
1

如果打开数据库调试,来自数据库的错误将被路由到 Exceptions 核心类,并exit()在之后调用,这意味着脚本甚至永远不会达到您的if条件。

打开application/config/database.php并尝试设置db_debug为false。无论如何,这对于生产网站来说是个好主意,因为您不希望任何 SQL 查询问题来发布有关您的数据库结构的信息。

此外,不相关的,在双引号内使用时要小心$,因为它会被解析为一个变量(即使是一堆连续的——它实际上是一个变量变量变量变量......)。

于 2013-04-07T03:05:37.137 回答
1

如果将结果设置在try块之外怎么办?或三元运算符:

$result = $this->db->insert('email', $new_email);
try {
  $result = ($result) ? $result || false;  
  if ($result) {
    $id = $this->db->insert_id();    
  } else {
    throw new Exception("$$$$$$$$$$$$$Log database error");
  }
} catch (Exception $e) {
  log_message('error',$e->getMessage());
  return;
}

$result就像@jcorry 说的那样,如果不知道真正的价值是什么,就很难知道。

于 2013-04-07T03:07:55.707 回答
1
$db['default']['db_debug'] = FALSE;

https://forum.codeigniter.com/archive/index.php?thread-8484.html

于 2019-01-04T09:56:54.290 回答
0

如果您查看 CodeIgniter 的代码,您会发现它在 bot system/core 和 ci_system/core 文件夹中的 CodeIgniter.php 中设置了自己的错误处理。

/*
 * ------------------------------------------------------
 *  Define a custom error handler so we can log PHP errors
 * ------------------------------------------------------
 */
    set_error_handler('_error_handler');
    set_exception_handler('_exception_handler');
    register_shutdown_function('_shutdown_handler');

前两个函数处理错误处理。为了让你的 try..catch 块工作,你只需要关闭它。

使用restore_error_handlerrestore_exception_handler函数,我们可以将这些错误处理函数重置为默认值。

    restore_error_handler();
    restore_exception_handler();

或者...如果您想保留错误处理程序以便以后恢复它们。

    //Disable CodeIgniter error handling so we can use try catch blocks
    $errorHandlers = array();
    do {
        $errorHandler = set_error_handler(function() {}); //Get the current handler
        array_push($errorHandlers, $errorHandler); //Store the handler so that it can be restored if necessary
        for ($i = 0; $i < 2; $i++) { //We have to reset twice to get to the previous handler since we added a dummy handler
            restore_error_handler();
        }
    }
    while (!is_null($errorHandler)); //Is null when there are no handlers
    $exceptionHandlers = array(); //Do the same with exceptions
    do {
        $exceptionHandler = set_exception_handler(function() {});
        array_push($exceptionHandlers, $exceptionHandler);
        for ($i = 0; $i < 2; $i++) {
            restore_exception_handler();
        }
    }
    while (!is_null($exceptionHandler));

    try {
        //Your code goes here
    }
    catch (Error $e) {
        //Handle error
    }
    catch (Exception $e) {
        //Handle exception
    }

    //Restore all error handlers
    foreach ($errorHandlers as $errorHandler) {
        if (isset($errorHandler)) {
            set_error_handler($errorHandler);
        }
    }
    foreach ($exceptionHandlers as $exceptionHandler) {
        if (isset($exceptionHandler)) {
            set_exception_handler($exceptionHandler);
        }
    }

如果需要,我们可以禁用所有自定义错误处理程序并存储它们以进行恢复。

如果设置了其他错误处理程序,我会在保存和恢复时使用循环。这样,您可以恢复所有错误处理程序,因为其他地方可能有类似的代码会出于某些特定目的返回到先前的错误处理程序,并且它将被保留。

于 2018-09-05T17:41:59.707 回答