【问题标题】:Converting errors to exceptions: design flaw?将错误转换为异常:设计缺陷?
【发布时间】:2011-03-26 10:42:46
【问题描述】:

我最近遇到了一些代码,它们使用自定义错误处理程序将任何 PHP 错误转换为通用应用程序异常。还定义了一个自定义异常处理程序,如果它在特定的错误代码范围内,它将记录异常。示例:

class AppException extends Exception
{

}

function error_handler($errno, $errstr, $errfile, $errline)
{
    throw new AppException($errstr, $errno);
}

function exception_handler($exception)
{
    $min = ...;
    $max = ...;

    if ($exception->getCode() >= $min && $exception->getCode() <= $max)
    {
        // log exception
    }
}

set_error_handler('error_handler');
set_exception_handler('exception_handler');

$a[1]; // throws exception

问题是我看到了类似的东西:

try
{
    do_something();
}
catch (AppException $exception)
{
}

这意味着实际编程错误和“异常”行为之间没有区别。在进一步挖掘后,我发现部分代码是围绕 PHP 错误代表“异常”行为的想法而设计的,例如:

...

function my_function($param1, $param2)
{
    // do something great
}

try
{
    my_function('only_one_param');
}
catch (AppException $exception)
{
}

这最终会混淆错误和应用程序界面的设计。

您对以这种方式处理错误有何看法?是否值得将 PHP 的原生错误转化为异常?在上述情况下,围绕这个想法设计代码库时,你会怎么做?

【问题讨论】:

    标签: php exception exception-handling interface error-handling


    【解决方案1】:

    就个人而言,我一直这样做。唯一的区别是,在我的error_handler 函数中,我首先检查错误是否为E_NOTICE,如果不是则仅抛出(无论如何我都会记录通知)...

    我会将 AppException 更改为扩展 ErrorException... 之类的东西:PhpRuntimeErrorException extends ErrorException 仅用于 PHP 错误...原因是它更具可读性(更容易说出什么PhpRuntimeErrorException 不需要弄清楚它被抛出的位置)。另一个原因是ErrorException 将存储生成行/文件/等信息,它不会存储在其他地方(因为回溯从throw 行开始)...

    那么,你可以“尝试”这样的代码:

    try {
        $f = fopen('foo.bar', 'r');
        $ret = '';
        while ($data = fread($f)) {
            $ret .= process($data);
        }
        fclose($f);
        return '';
    } catch (PHPRuntimeErrorException $e) {
        throw new RuntimeException('Could not open file');
    } catch (ProcessException $e) {
        fclose($f);
        throw new RuntimeException('Could not process data');
    }
    return $ret;
    

    我还让我的默认异常处理程序生成一个 500 服务器错误页面。那是因为任何异常都应该被捕获,如果没有,那就真的是服务器错误......

    只是我的经验和意见...

    【讨论】:

    • 是的,这一切听起来都不错,首先想到的是把 AppException 更改为 PHP 错误特定的异常。尽管我想知道此解决方案与仅在自定义错误处理程序中生成 500 服务器错误之间有什么区别,而不使用实际错误的异常。另外,这样做有什么开销吗?
    • 嗯,这与开销无关。我只为未处理的异常生成 500 个错误页面。很多时候我会发现 PHP 错误并继续处理。例如,如果 DomDocument 无法解析 XML 字符串,它将引发警告。所以我捕获了那个错误,并用它来触发文件try { $dom-&gt;loadXml($xml); } catch (PhpRuntimeErrorException $e) { $xml = XmlCleaner::clean($xml); $dom-&gt;loadXml($xml); } 的清理和重新解析我不想运行XmlCleaner,因为它真的很贵。所以我让 PHP 错误告诉我什么时候做...
    【解决方案2】:

    PHP 社区对此进行了一些争论。我相信一般的想法是错误是内部 PHP 函数抛出的东西,是你真正需要修复的编码问题;而异常是您的应用程序代码抛出的东西,您可能只需要“处理”。

    但是,一些较新的 SPL 扩展(往往更面向对象)确实使用异常来处理以前可能引发错误的事情,因此存在一些灰色区域。

    还有一个 PHP 核心类 ErrorException - http://www.php.net/manual/en/class.errorexception.php 看起来比你的代码示例更容易使用,如果这是你想走的路线。

    【讨论】:

    • 这也是我的想法...我认为混淆来自于有多种错误处理机制并且没有真正的标准这一事实。我确实查看了 ErrorException 类,这看起来是不错的第一步。
    • 嗯,对某些人来说,是的。就像你打电话给fopen($foo) 一样,你应该得到一个错误,因为你缺少第二个参数。但是如果你打电话给parse_url($url),而$url 是一个格式错误的url,你也会在那里收到警告。所以在某些情况下,是的,它们是编码问题。但是有大量与编码无关的“运行时”问题......所以这实际上只是你想如何处理错误的问题(我喜欢我的例外。如果你不这样做,那很好也是。只要你始终如一且有条不紊,这就是最终真正重要的一切)......
    • 当然,我认为这是一个很好的案例,我在考虑严格的编程错误,但这样更有意义。
    【解决方案3】:

    我将所有内容都转换为异常,包括通知。没有理由允许异常继续正常进行。未定义的变量或偏移量?这是个问题。

    https://github.com/KyleWolfe/PHPErrorNet

    【讨论】:

    • >> "未定义的变量或偏移量?这是个问题。" UUhmm...如果偏移处的数据是可选的呢?
    • 哈哈。当有大量变量要检查时,我不会打扰。我做$foo = $_GET['foo']; 然后在页面的某个地方if(isset($foo))。这会产生警告,但谁在乎。 :)
    • @chx101 很明显,您从来不需要处理每秒生成如此多通知的站点,您无法找到真正的错误。仅处理通知就可以大大加快网站速度。但这不是重点。
    • @Addaddinsane 哦,我当然知道。这还取决于您正在处理的项目类型。例如,在创建 API 服务器时,您不能留下错误和警告或任何未处理的系统输出。我可以给你讲个故事,但这也不重要。
    • 链接已失效 (404)。
    猜你喜欢
    • 1970-01-01
    • 2015-11-19
    • 2013-03-14
    • 2016-10-07
    • 2017-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多