首先,我要赞扬你看看PHP中的标准错误方法。遗憾的是error_log有一些限制,你发现。
这是一个长的答案,阅读,了解:
>错误
>直接记录错误vs trigger_error和set_error_handler
>哪里好错误坏 – 致命错误。
>异常
> SPL
>他们怎么办?
>代码
>设置
>使用
TL; DR使用trigger_error提高错误和set_error_handler记录它们。
错误
当事情不如你的程序中的预期,你会经常想提出一个错误,以便通知某人或某事。错误是指程序可能继续,但有一些值得注意,可能有害或错误发生的情况。在这一点上,许多人想要立即记录他们的日志包的选择。我相信这是完全错误的事情。我建议使用trigger_error引发错误,以便可以使用由set_error_handler设置的回调来处理错误。让我们比较这些选项:
直接记录错误
所以,你已经选择了你的日志包。现在,您可以在代码中发生错误的地方将调用传播到记录器。让我们看看你可能做的一个单一的电话(我会使用类似的记录器,在杰克的答案):
Logger :: getLogger(‘standard’) – > error(‘Ouch,this hurts’);
你需要什么来运行这段代码?
Class: Logger
Method: getLogger
Return: Object with method 'error'
这些是使用此代码所需的依赖关系。每个想要重用这个代码的人都必须提供这些依赖。这意味着标准的PHP配置将不再足以重新使用您的代码。在最好的情况下,使用依赖注入仍然需要一个logger对象传递到所有可能发出错误的代码。
我们可以看到,直接记录错误是坏的。
trigger_error来救援
PHP有一个称为trigger_error的函数,可以像标准函数那样引发错误。与其一起使用的错误级别在error level constants中定义。作为用户,必须使用用户错误之一:E_USER_ERROR,E_USER_WARNING或缺省值E_USER_NOTICE(为标准函数保留其他错误级别等)。使用标准PHP函数来引发错误允许代码重用于任何标准PHP安装!我们的代码不再负责记录错误(只是确保它被提出)。
使用trigger_error,我们只执行一半的错误记录进程(提高错误),并保存响应错误处理程序的错误的责任,这将在下面覆盖。
错误处理程序
我们用set_error_handler函数设置一个自定义错误处理程序(参见代码设置)。此自定义错误处理程序将替换标准的PHP错误处理程序,该错误处理程序通常会在Web服务器错误日志中记录消息,具体取决于PHP配置我们仍然可以通过在我们的自定义错误处理程序中返回false来使用此标准错误处理程序。
自定义错误处理程序有一个责任:响应错误(包括您要做的任何日志记录)。在自定义错误处理程序中,您具有对系统的完全访问权限,并且可以运行所需的任何类型的日志记录。事实上,任何使用Observer设计模式的记录器都会正常工作(我不打算这样做,因为我认为它是次要的)。这应该允许你挂钩新的日志观察者发送输出到你需要它。
你可以完全控制,在你的代码的一个可维护的部分做你喜欢的错误。错误日志现在可以从一个项目到另一个项目或从一个页面到另一个页面快速方便地更改。有趣的是,即使@被抑制的错误使它的自定义错误处理程序的errno为0,如果遵守error_reporting掩码不应该报告。
当好错误去坏 – 致命错误
不可能从某些错误继续。以下错误级别无法通过自定义错误处理程序处理: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.例外
异常可以以非常类似于基本错误的方式处理。代替trigger_error,你的代码会抛出一个异常(手动使用throw new Exception或者从标准函数调用)。使用set_exception_handler定义要用于处理异常的回调。
SPL
标准PHP库(SPL)提供exceptions.它们是我提出异常的首选方法,因为像trigger_error,它们是PHP的标准部分,不会对代码引入额外的依赖。
与他们做什么?
当抛出异常时,有三个选择:
>捕捉它并修复它(代码然后继续,好像没有发生什么)。
>捕捉它,附加有用的信息并重新抛出它。
>让它冒泡到更高的水平。
在堆栈的每个级别进行这些选择。最终一旦它冒泡到最高级别,set_exception_handler设置的回调将被执行。这是你的日志代码所属的地方(与错误处理相同的原因),而不是在你的代码中的catch语句。
代码
建立
错误处理程序
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附加:
观察下面code_that_can_generate_exception()不知道$ context。在这个级别的catch块有更多的信息,它可以附加到异常,如果它是有用的rethrowing它。
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.