首先,我想赞扬您查看PHP中的标准误差方法。不幸的是,正如您发现的那样,有一些限制。error_log
这是一个很长的答案,请继续阅读以了解:
- 错误
- 直接记录错误与
trigger_error
set_error_handler
- 好错误变坏的地方 - 致命错误。
- 异常
- 法典
TL;DR用于引发错误和记录错误。trigger_error
set_error_handler
1. 错误
当程序中的情况没有按预期进行时,您经常会希望引发错误,以便通知某人或某事。错误是指程序可能继续,但发生了值得注意的,可能是有害的或错误的情况。此时,许多人希望立即使用他们选择的日志记录包来记录错误。我认为这完全是错误的做法。我建议 使用 来引发错误,以便可以使用 由 设置的回调进行处理。让我们比较这些选项:trigger_error
set_error_handler
直接记录错误
因此,您已选择日志记录包。现在,只要代码中发生错误,就可以将调用分散到记录器。让我们看一下您可能拨打的单个电话(我将使用与Jack答案中的记录器类似的记录器):
Logger::getLogger('standard')->error('Ouch, this hurts');
运行此代码需要什么?
Class: Logger
Method: getLogger
Return: Object with method 'error'
这些是使用此代码所需的依赖项。每个想要重用此代码的人都必须提供这些依赖项。这意味着标准的PHP配置将不再足以重用您的代码。在最佳情况下,使用依赖关系注入,您仍然需要将记录器对象传递到所有可能发出错误的代码中。
此外,除了代码负责的任何内容之外,它还负责记录错误。这违背了单一责任原则。
我们可以看到直接记录错误是不好的。
trigger_error救援
PHP有一个名为trigger_error
函数可以用来引发错误,就像标准函数一样。与它一起使用的错误级别在错误级别常量中定义。作为用户,您必须使用其中一个用户错误:或默认值(为标准函数等保留其他错误级别)。使用标准的PHP函数来引发错误允许代码在任何标准的PHP安装中重复使用!我们的代码不再负责记录错误(仅确保它已引发)。E_USER_ERROR
E_USER_WARNING
E_USER_NOTICE
使用时,我们只执行一半的错误记录过程(引发错误),并将响应错误的责任留给错误处理程序,这将在下面介绍。trigger_error
错误处理程序
我们使用set_error_handler
函数设置自定义错误处理程序(请参阅代码设置)。此自定义错误处理程序取代了标准的 PHP 错误处理程序,该处理程序通常根据 PHP 配置设置在 Web 服务器错误日志中记录消息。我们仍然可以通过在自定义错误处理程序中返回来使用此标准错误处理程序。false
自定义错误处理程序只有一个职责:响应错误(包括要执行的任何日志记录)。在自定义错误处理程序中,您具有对系统的完全访问权限,并且可以运行所需的任何类型的日志记录。实际上,任何使用观察者设计模式的记录器都可以(我不打算深入讨论,因为我相信它是次要的)。这应该允许您挂接新的日志观察器,以将输出发送到您需要它的位置。
您可以完全控制对代码的单个可维护部分中的错误执行您喜欢的操作。现在可以在项目之间快速轻松地更改错误日志记录,也可以在单个项目中从一个页面更改为另一个页面。有趣的是,即使被抑制的错误也以0的精度进入自定义错误处理程序,如果error_reporting
掩码得到尊重,则不应报告。@
errno
当好错误变坏时 - 致命错误
无法从某些错误继续。无法从自定义错误处理程序处理以下错误级别:、 、 、 、 、 。当这些类型的错误由标准函数调用触发时,将跳过自定义错误处理程序并关闭系统。这可以通过以下方式生成:E_ERROR
E_PARSE
E_CORE_ERROR
E_CORE_WARNING
E_COMPILE_ERROR
E_COMPILE_WARNING
call_this_function_that_obviously_does_not_exist_or_was_misspelt();
这是一个严重的错误!无法从中恢复,并且系统即将关闭。我们唯一的选择
是register_shutdown_function处理关闭。但是,每当脚本完成(成功和不成功)时,都会执行此函数。使用这个和error_get_last
当最后一个错误是致命错误时,可以记录一些基本信息(此时系统几乎关闭)。发送正确的状态代码并显示您选择的“内部服务器错误类型”页面也很有用。
2. 例外情况
异常的处理方式与基本错误非常相似。而不是由代码引发异常(使用或从标准函数调用手动)。使用set_exception_handler
定义要用于处理异常的回调。trigger_error
throw new Exception
声压级
标准 PHP 库 (SPL) 提供了例外情况。它们是我提出异常的首选方式,因为它们是PHP的标准部分,不会给代码引入额外的依赖关系。trigger_error
如何处理它们?
当引发异常时,可以做出三种选择:
- 捕获它并修复它(然后代码继续,好像没有发生任何不好的事情)。
- 抓住它,附加有用的信息,然后重新抛出它。
- 让它冒泡到一个更高的层次。
在堆栈的每个级别上,都会做出这些选择。最终,一旦它冒泡到最高级别,您设置的回调将被执行。这是日志记录代码所属的位置(出于与错误处理相同的原因),而不是分散在代码中的语句中。set_exception_handler
catch
3. 代码
设置
错误处理程序
function errorHandler($errno , $errstr, $errfile, $errline, $errcontext)
{
// Perform your error handling here, respecting error_reporting() and
// $errno. This is where you can log the errors. The choice of logger
// that you use is based on your preference. So long as it implements
// the observer pattern you will be able to easily add logging for any
// type of output you desire.
}
$previousErrorHandler = set_error_handler('errorHandler');
异常处理程序
function exceptionHandler($e)
{
// Perform your exception handling here.
}
$previousExceptionHandler = set_exception_handler('exceptionHandler');
关断功能
function shutdownFunction()
{
$err = error_get_last();
if (!isset($err))
{
return;
}
$handledErrorTypes = array(
E_USER_ERROR => 'USER ERROR',
E_ERROR => 'ERROR',
E_PARSE => 'PARSE',
E_CORE_ERROR => 'CORE_ERROR',
E_CORE_WARNING => 'CORE_WARNING',
E_COMPILE_ERROR => 'COMPILE_ERROR',
E_COMPILE_WARNING => 'COMPILE_WARNING');
// If our last error wasn't fatal then this must be a normal shutdown.
if (!isset($handledErrorTypes[$err['type']]))
{
return;
}
if (!headers_sent())
{
header('HTTP/1.1 500 Internal Server Error');
}
// Perform simple logging here.
}
register_shutdown_function('shutdownFunction');
用法
错误
// Notices.
trigger_error('Disk space is below 20%.', E_USER_NOTICE);
trigger_error('Disk space is below 20%.'); // Defaults to E_USER_NOTICE
// Warnings.
fopen('BAD_ARGS'); // E_WARNING fopen() expects at least 2 parameters, 1 given
trigger_error('Warning, this mode could be dangerous', E_USER_WARNING);
// Fatal Errors.
// This function has not been defined and so a fatal error is generated that
// does not reach the custom error handler.
this_function_has_not_been_defined();
// Execution does not reach this point.
// The following will be received by the custom error handler but is fatal.
trigger_error('Error in the code, cannot continue.', E_USER_ERROR);
// Execution does not reach this point.
异常
之前的三个选项中的每一个都以通用的方式在这里列出,修复它,附加到它并让它冒泡。
1 可修复:
try
{
$value = code_that_can_generate_exception();
}
catch (Exception $e)
{
// We decide to emit a notice here (a warning could also be used).
trigger_error('We had to use the default value instead of ' .
'code_that_can_generate_exception\'s', E_USER_NOTICE);
// Fix the exception.
$value = DEFAULT_VALUE;
}
// Code continues executing happily here.
2 追加:
在下面观察如何不知道.此级别的 catch 块具有更多信息,如果通过重新抛出异常有用,则可以将其附加到异常中。code_that_can_generate_exception()
$context
try
{
$context = 'foo';
$value = code_that_can_generate_exception();
}
catch (Exception $e)
{
// Raise another exception, with extra information and the existing
// exception set as the previous exception.
throw new Exception('Context: ' . $context, 0, $e);
}
3 让它冒泡:
// Don't catch it.