php - Doctrine DBAL 中的错误处理与 PHP PDO 的比较

标签 php pdo exception-handling doctrine-orm dbal

有了 PDO,我们有 \PDO::ATTR_ERRMODE , 并将其设置为 \PDO::ERRMODE_EXCEPTION 我们能够获得详细的异常堆栈跟踪 (getTrace)。

DBAL 怎么样?如何在 DBAL 级别设置它如何抛出错误?

DBAL 是 PDO 实例的包装器,DBAL 大多数 PDO 方法的工作原理相同,是否还有 ATTR_ERRMODE 或其他类似的报告控制方法?

我想使用 set_error_handler为了更好地控制错误的行为方式以及 ERRMODE_EXCEPTION 级别,它非常有用。

在 PDO 中:

<?php
$dsn = 'mysql:host='.$_SESSION['options']['host'].';port='.$_SESSION['options']['port'].';dbname='.$_SESSION['options']['dbname'].';charset='.$_SESSION['options']['charset'];
try {
    $conn = new \PDO($dsn, $_SESSION['options']['user'], $_SESSION['options']['pass']);
    $conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); // how to set this line in DBAL?
} catch (\PDOException $e) {
    trigger_error($e->getMessage(), E_USER_ERROR);
}
?>

在 DBAL 中也是如此:

<?php
require_once "lib/autoload.php";
$config = new \Doctrine\DBAL\Configuration();
$params = array(
    'dbname' => $_SESSION['options']['dbname'],
    'user' => $_SESSION['options']['user'],
    'password' => $_SESSION['options']['pass'],
    'host' => $_SESSION['options']['host'],
    'port' => $_SESSION['options']['port'],
    'driver' => 'pdo_mysql',
    'charset' => $_SESSION['options']['charset'],
);
try {
    $conn = \Doctrine\DBAL\DriverManager::getConnection($params, $config);
} catch (\Exception $e) {
    trigger_error($e->getMessage(), E_USER_ERROR);
}
?>

学说 DBAL 版本:2.5.1

最佳答案

DBAL 如何抛出错误

我检查了一下,PDO 相关驱动程序的 DBAL 默认将 PDO::ATTR_ERRMODE 设置为 PDO::ERRMODE_EXCEPTION(herehere ), 所以我们有详细的堆栈跟踪,就像在 PDO 中一样。

事实上,DBAL 异常甚至比 PDO 更详细 - DBAL 在错误描述中添加了一些信息(例如 here)。

更改错误级别的选项

看来,DBAL 缺少改变它抛出错误的级别的功能。
无法将 PDO::ATTR_ERRMODE 更改为 PDO::ERRMODE_SILENTPDO::ERRMODE_WARNING
理论上,它应该可以通过 driverOptions option 获得,像这样:

$params = array(
    'dbname' => $options['dbname'],
    'user' => $options['user'],
    'password' => $options['pass'],
    'host' => $options['host'],
    'port' => $options['port'],
    'driver' => 'pdo_mysql',
    'charset' => $options['charset'],
    'driverOptions' => array(
        3 => 0 //here "3" is value of constant ATTR_ERRMODE, and "0" value of constant ERRMODE_SILENT
    )
);

它会工作,但在连接声明后不久,DBAL 会覆盖 PDO::ATTR_ERRMODE(here)。
在 PDO 中也有 setAttribute 方法,通过它我们可以设置 PDO::ATTR_ERRMODE,但不幸的是 DBAL 没有实现 setAttribute 方法.

如何控制DBAL中的错误

在 DBAL 中,我们已经有了最好的错误级别,我们可以捕获所有内容并更好地控制我们可以使用 set_error_handler:

<?php
/**
 * Error handler
 *
 * @param int $err_code the numeric error code
 * @param str $err_str description of the error
 * @param str $err_file the name of the file that contains the error
 * @param int $err_line the line number of the error
 * @param str $err_context details of the error
 */

function errorHandler($err_code, $err_str, $err_file, $err_line, $err_context) {
global $_SESSION;
    $_SESSION['errorCounter']++;
    $error_types = array (
        E_WARNING           => 'WARNING',
        E_NOTICE            => 'NOTICE',
        E_USER_ERROR        => 'USER ERROR',
        E_USER_WARNING      => 'USER WARNING',
        E_USER_NOTICE       => 'USER NOTICE',
        E_STRICT            => 'STRICT',
        E_DEPRECATED        => 'DEPRECATED',
        E_USER_DEPRECATED   => 'USER DEPRECATED'
    );
    $error_type = isset($error_types[$err_code]) ? $error_types[$err_code] : 'UNKNOWN ERROR TYPE['.$err_code.']';
    $err = "\n>--------------------------------------------------------------------";
    $err .= "\n".'EXCEPTION #'.$_SESSION['errorCounter'].':';
    $err .= "\n\n---- PHP ".$error_type.": ----";
    $err .= "\n".$err_str;

    //$err .= print_r($err_context, 1);
    if (isset($err_context['e'])){
        $err .= "\n\n---- STACKTRACE: ----";
        $dir_root = $_SERVER["DOCUMENT_ROOT"];
        $err .=  "\nroot: " . $dir_root;
        foreach ($err_context['e']->getTrace() as $a => $b) {
            $err .= "\n" . strval($a) . '# ';
            foreach ($b as $c => $d) {
                switch($c){
                    case 'file':
                        $err .=  str_replace($dir_root,'(root)',str_replace('\\','/',$d));
                        break;
                    case 'line':
                        $err .=  '(' . $d . "); ";
                        break;
                    case 'function':
                        $err .=  $c . ' ' . $d . "; ";
                        break;
                    case 'class':
                        $err .=  $c . ' ' . $d . "; ";
                        break;
                    case 'type':
                        $err .=  $c . ': ' . $d . "; ";
                        break;
                    case 'args':
                        foreach ($d as $e => $f){
                            $e = is_object($e) ? 'object' : is_array($e) ? 'array' : trim(preg_replace('/\s+/', ' ', $e));//do not return objects, arrays and change new lines to space
                            $f = is_object($f) ? 'object' : is_array($f) ? 'array' : trim(preg_replace('/\s+/', ' ', $f));//do not return objects, arrays and change new lines to space
                            $err .= 'args-' . $e . ': ' . $f . '; ';
                        }
                        break;
                }
            }
        }
    }
    else {
        $err .= "\n\n---- LOCATION: ----";
        $err .= "\n".$err_file.'(' . $err_line . ')';
    }

    $err .= "\n\n---- CONNECTION: ----";
    $err .= "\n".'host: '.$_SERVER['SERVER_NAME'];
    $err .= "\n".'client: '.$_SERVER['REMOTE_ADDR'];
    $err .= "\n".'timestamp: '.date("d-m-Y h:i:s A");
    $err .= "\n<--------------------------------------------------------------------\n";



    if (ini_get('log_errors')) {
        error_log($err, 0);
        if($err_code == E_USER_ERROR) {
            if (!$_SESSION['options']['debug']) {
                //send email with error
            }
        }
    }

    if ($_SESSION['options']['debug'])
        print("\n<pre>".$err."</pre>\n");

    return true;
}

set_error_handler("errorHandler");

关于php - Doctrine DBAL 中的错误处理与 PHP PDO 的比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29522915/

相关文章:

mysql - 将 2 个数字相加,一个来自数据库结果,另一个来自 post 数组

PHP PDO 在更新时转义双引号

c++ - 从构造函数中捕获异常意味着我的实例之后超出了范围

java - 在 While 循环中 try catch

php - 提交抽象类和子类的最佳实践?

PHP DateTime::createFromFormat 不解析 ISO 8601 日期时间

php - PDO,准备使用

python - 为什么我们需要 Python 中的 "finally"子句?

php - 脱脂框架 : the F3 Autoloader

php - 无法将 php 变量从 Controller 渲染到 yii2 中查看