首先,我要赞扬您查看PHP中的标准错误方法。不幸的是
error_log,您发现了一些限制。
这是一个很长的答案,请继续阅读以下内容:
- 失误
- 直接记录错误vs
trigger_error
和set_error_handler
- 好的错误会变坏的地方-致命错误。
- 直接记录错误vs
- 例外情况
- 声压级
- 该怎么办?
- 码
- 设定
- 用法
TL; DR 使用
trigger_error筹集的错误和
set_error_handler用于记录他们。
1.错误
当事情在程序中没有按预期进行时,您通常会想引发一个错误,以便有人或某事得到通知。错误是指程序可以继续运行,但发生了一些值得注意的,可能有害或错误的情况。此时,许多人希望使用所选的日志记录包立即记录错误。我相信这完全是错误的事情。我建议使用
trigger_error引发错误,以便可以通过设置的回调来处理该错误
set_error_handler。让我们比较一下这些选项:
直接记录错误
因此,您已经选择了日志记录包。现在,您可以将代码中发生错误的任何地方分散到记录器中。让我们看一下您可能会打的一个电话(我将使用与Jack回答中类似的记录器):
Logger::getLogger('standard')->error('Ouch, this hurts');您需要什么来运行此代码?
**类** :记录器 **方法** :getLogger **返回** :具有方法“错误”的对象
这些是使用此代码所需的依赖项。每个想重用此代码的人都必须提供这些依赖项。这意味着标准的PHP配置将不再足以重用您的代码。在最好的情况下,使用依赖注入,您仍然需要将logger对象传递到所有可能产生错误的代码中。
另外,除了代码负责什么之外,它还负责记录错误。这违背了单一责任原则。
我们可以看到 直接记录错误是不好的 。
trigger_error进行救援
PHP有一个称为的函数
trigger_error,可以像标准函数一样用来引发错误。与它一起使用的错误级别在错误级别常量中定义。当你必须使用用户错误的一个用户:
E_USER_ERROR,
E_USER_WARNING或默认值
E_USER_NOTICE(其他错误级别被保留用于标准的功能等)。使用标准的PHP函数引发错误,可使代码在任何标准的PHP安装中重复使用!我们的代码不再负责记录错误(仅确保已引发错误)。
使用
trigger_error我们,我们仅执行错误记录过程的一半(引发错误),并为错误处理程序节省了响应错误的责任,这将在后面介绍。
错误处理程序
我们使用
set_error_handler函数设置了一个自定义错误处理程序(请参阅代码设置)。此自定义错误处理程序代替了通常根据PHP配置设置将标准消息记录在Web服务器错误日志中的标准PHP错误处理程序。我们仍然可以通过
false在自定义错误处理程序中返回来使用此标准错误处理程序。
定制错误处理程序有一个责任:响应错误(包括您要执行的任何日志记录)。在自定义错误处理程序中,您具有对系统的完全访问权限,并且可以运行所需的任何类型的日志记录。几乎所有使用Observer设计模式的记录器都可以(我不打算讨论它,因为我认为它是次要的)。这应该允许您挂接新的日志观察器,以将输出发送到所需的位置。
您具有完全的控制权,可以在代码的单个可维护部分中对错误进行处理。现在,可以在项目之间或在单个项目中的页面之间快速,轻松地更改错误日志。有趣的是,即使
@被抑制的错误也以
errno0表示到达自定义错误处理程序,如果
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 newException或从一个标准的函数调用)。使用
set_exception_handler定义要用来处理与异常的回调。
声压级
标准PHP库(SPL)提供了exceptions。它们是引发异常的首选方式,因为就像
trigger_error它们是PHP的标准部分一样,它不会为您的代码引入额外的依赖关系。
该怎么办?
引发异常时,可以做出三种选择:
- 捕获并修复它(然后代码继续运行,好像没有发生任何不好的事情一样)。
- 抓住它,添加有用的信息,然后重新抛出。
- 让它上升到更高的水平。
在堆栈的每个级别都进行了这些选择。最终,一旦达到最高级别,您设置的回调
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 giventrigger_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 pre, cannot continue.', E_USER_ERROR);// Execution does not reach this point.例外情况
以前列出的三个选择中的每一个都以通用的方式列出在这里,对其进行修复,追加并使其冒出。
1可修复:
try{ $value = pre_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 ' . 'pre_that_can_generate_exception's', E_USER_NOTICE); // Fix the exception. $value = DEFAULT_VALUE;}// Code continues executing happily here.2附加:
下面观察如何
pre_that_can_generate_exception()不知道的
$context。该级别的catch块具有更多信息,如果可以通过将其重新抛出有用,则可以将其附加到异常上。
try{ $context = 'foo'; $value = pre_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.



