【问题标题】:CodeIgniter: Try Catch is not working in model classCodeIgniter:Try Catch 在模型类中不起作用
【发布时间】:2013-04-07 02:52:46
【问题描述】:

我对该列有一个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 

我不知道有什么问题。

【问题讨论】:

  • 你能更具体地描述一下究竟是什么不工作吗?会发生什么而不是您所期望的?
  • 也许 $result 不是假的?

标签: php codeigniter


【解决方案1】:

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 中)使用持久连接作为打开的事务,其他会话特定的数据库状态将被其他会话拾取/继续。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      如果您将结果设置在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 所说的那样。

      【讨论】:

        【解决方案4】:

        【讨论】:

          【解决方案5】:

          如果您查看 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);
                  }
              }
          

          我们可以禁用所有自定义错误处理程序并将它们存储起来,以便在需要时恢复。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-01-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多