Php 将错误转换为异常:设计缺陷?

Php 将错误转换为异常:设计缺陷?,php,exception,exception-handling,interface,error-handling,Php,Exception,Exception Handling,Interface,Error Handling,我最近遇到一些代码,它们使用自定义错误处理程序将任何PHP错误转换为通用应用程序异常。还定义了一个自定义异常处理程序,如果异常在特定的错误代码范围内,它将记录该异常。例如: class AppException extends Exception { } function error_handler($errno, $errstr, $errfile, $errline) { throw new AppException($errstr, $errno); } function e

我最近遇到一些代码,它们使用自定义错误处理程序将任何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
这意味着实际编程错误和“异常”行为之间没有区别。在进一步挖掘之后,我发现部分代码是围绕PHP错误表示“异常”行为的思想设计的,例如:

...

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

try
{
    my_function('only_one_param');
}
catch (AppException $exception)
{
}
这最终会混淆错误和应用程序界面的设计


你对这样处理错误有什么看法?是否值得将PHP的本机错误转化为异常?在上面这样的情况下,如果代码库是围绕这个想法设计的,你会怎么做

就我个人而言,我一直都这样做。唯一的区别是,在我的
error\u处理程序
函数中,我首先检查错误是否是
E\u通知
,如果不是,则仅抛出(无论如何,我会记录通知)

我会将
AppException
更改为扩展
ErrorException
的内容。。。类似于:
PhpRuntimeErrorException扩展了ErrorException
,它只用于PHP错误。。。原因是它更具可读性(更容易判断
PhpRuntimeErrorException
是什么,而无需找出抛出的位置)。另一个原因是,
ErrorException
将存储生成行/文件/etc信息,而不会存储在其他位置(因为回溯从
抛出
行开始)

因此,您可以“尝试”这样的代码:

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服务器错误页面。这是因为任何异常都应该被捕获,如果它们没有被捕获,那实际上是一个服务器错误


仅凭我的经验和观点…

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

然而,一些较新的SPL扩展(倾向于更面向对象)确实对以前可能抛出错误的东西使用异常,因此存在一些灰色区域


还有一个PHP核心类ErrorException,如果这是一条您想要走的路线,它看起来比您的代码示例更易于使用。

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


是的,所有这些听起来都不错,首先想到的是将AppException更改为特定于PHP错误的异常。虽然我想知道这个解决方案和只在自定义错误处理程序中生成500服务器错误而不使用实际错误的异常之间有什么区别。还有,这样做有没有开销?嗯,这不是开销的问题。我只为未处理的异常生成500个错误页。我经常发现PHP错误并继续处理。例如,如果DomDocument无法解析XML字符串,它将发出警告。因此,我捕获该错误,并使用它触发文件的清理和重新解析
尝试{$dom->loadXml($xml);}catch(PhpRuntimeErrorException$e){$xml=XmlCleaner::clean($xml);$dom->loadXml($xml);}
我不想运行
XmlCleaner
,因为它确实非常昂贵。所以我让PHP错误告诉我什么时候去做……这也是我的想法……我认为混淆是因为存在多种错误处理机制,并且没有真正的标准。我确实看过ErrorException类,这看起来是一个很好的第一步。对一些人来说,是的。例如,如果调用
fopen($foo)
,您应该会得到一个错误,因为您缺少第二个参数。但是如果您调用
parse\u url($url)
,并且
$url
是一个格式错误的url,您也会在那里得到警告。所以在某些情况下,是的,它们是编码问题。但是有大量与编码无关的“运行时”问题。。。因此,这实际上只是一个你想如何处理错误的问题(我喜欢我的例外。如果你不喜欢,那也很好。只要你始终如一、有条不紊,这才是最终真正重要的)…当然,我认为这是一个很好的例子,我一直在考虑严格的编程错误,但这更有意义。>>“未定义的变量或偏移量?这是一个问题。“UUhmm…如果偏移量处的数据是可选的呢?哈。当有大量变量要检查时,我不必费心。我会
$foo=$\u GET['foo'];
然后在页面的某个地方
if(isset($foo))
。这会产生警告,但谁在乎呢?:@chx101显然,你从来没有处理过一个每秒生成这么多通知的站点,你找不到真正的错误。仅仅处理通知就可以极大地加快站点的速度。但这不是重点。@Adaddinsane哦,我当然有。这还取决于你正在处理的项目类型h、 例如,在创建API服务器时,不能让错误和警告或任何系统输出未经处理。我可以告诉你一个故事,但这也离题了。链接已失效(404)。
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;