关闭或处理生产环境中的错误?

时间:2013-06-15 12:47:45

标签: php

与我的团队争吵之后,因为我们对这种情况都有不同的看法。什么时候关闭PHP错误消息,或者抑制某些抛出警告的功能,通知无论出于什么原因。

我理解每个人都说你应该在生产环境中关闭error_reporting,但这可能会导致一些不会被拾取的并发症。所以没有什么能得到修复。 PHP提供了许多不同的方法来控制错误消息。例如:

$Var = "Variable Is Set";

if (@$Var){ echo $Var; }

结束:

if (isset($Var)){ echo $Var; }

因为我们有一个set变量,所以这将成功回显..如果我们没有set变量,那么会抛出一个通知..那么使用哪一个?是设置还是错误抑制?

在生产环境中,哪一个更容易被使用?

error_reporting(0);

以上内容将关闭所有类型的PHP错误报告,即使遇到问题也不会显示任何错误消息。因此,在某些情况下,由于消息被破坏,这可能会导致代码因为未知原因而停止工作

或:

set_error_handler("");

上面启用了一个自定义错误处理程序,可以用来向用户优雅地显示错误,并使管理员能够记录详细的警告..但是,再一次,我知道的error_handler在致命时不会被调用错误被触发?

那么我的整体问题是什么?

处理生产环境中的错误或者只是将其关闭?这可以归结为我认为的最佳实践和偏好。但是这让我和我的团队感到困惑到了分歧的地步。

3 个答案:

答案 0 :(得分:5)

从不完全关闭错误报告。您执行关闭错误显示。在开发过程中必须直接将错误转储到屏幕上(除非你有其他方法可以解决所有错误),在生产中你需要相同的错误报告,而不是输出可见的错误,你想要它只记录它们。这可以使用PHP的错误报告配置设置完成。

如果您需要特殊的自定义错误处理/日志记录,请使用自定义错误处理程序。

对于@,您永远不会以某种方式编写应用程序,因为它会对您依赖的行为产生实际错误。您以不会触发错误的方式编写所有内容。只有在无法避免可能的错误时才使用@,因为您无法以任何其他方式编写它,并且期望出错并且正在处理它;然后你所做的就是压制不可避免的错误信息。

答案 1 :(得分:3)

对不起,这不是一个明确的解决方案,但经过几年的反复试验,我提出了以下做法,这些做法都是我自己的,并且运作良好:

1 - 切勿使用@来抑制错误。切勿使用任何东西盲目隐藏或忽略所有错误。所有错误都很重要,不应忽略任何错误。

2 - 按照RafaSashi的建议,打开错误记录并关闭显示错误。

3 - 在PHP.INI中使用error_reporting = 2147483647激活所有错误报告。这将使PHP非常挑剔您可能做错的任何事情,帮助您了解更多信息并及时了解未来的语言弃用和更改。

4 - 您还可以创建自己的错误记录,以您想要的方式准确记录您想要的内容。查看error_log()的手册。如果您使用它,您甚至可以关闭,并开始手动记录,这将使您完全控制PHP的错误记录系统。

5 - 我在所有PHP代码中都使用OOP,所以我到处都使用异常,我建议大家都这样做。他们在简单的错误处理之前就已经光明了几年。使用此代码拦截代码中的所有错误并将其作为例外抛出:

set_error_handler('ErrorHandler');
function ErrorHandler($Code, $Message)
{
  throw new Exception($Message, $Code);
}

6 - 没有向用户显示任何错误是没有意义的。应该显示一些错误,一些应该隐藏,一些应该显示为一般问题(不要告诉用户确切的问题)。

a)应显示的错误:由用户引起的所有内容,例如无效的表单输入或错误的行为。这很明显,但应该提到。

b)应隐藏的错误:仅隐藏代码可以处理和纠正的错误。例如,您可以进行数据库连接,如果失败,您可以再试一次。如果第二次尝试成功,继续,没有人应该知道第一次尝试失败。如果需要,只需使用error_log()进行记录即可。有时,变量尚不存在,因此请使用isset()进行检查,并在需要时对其进行初始化。无需将此报告为错误。

c)应显示为通用的错误:大多数错误都属于此类别。您不会向用户显示PHP内存耗尽,或SMTP服务器脱机或数据库连接被拒绝等内容。只需学习如何使用try包装危险代码,使用catch捕获任何错误,并将消息转换为可以向用户显示的内容。例如:

try
{
  // Dangerous code ahead: we will try to connect to the database, but it 
  // can be offline.
  $mysqli = new mysqli("localhost", "user", "password", "database");
}
catch(Exception $e)
{
  // If we're here, something bad happened during connection. Let's handle it.

  // Notify staff, log error, do anything you can to get someone to quickly 
  // check the issue.
  SendMailAdmin("Database connection Error, check ASAP.");
  error_log("Database connection Error, check ASAP.");

  // And show the user some message. You don't need to tell him about any 
  // detail regarding what truly caused the error.
  die("A problem occurred in our servers. Our technical staff has been notified, 
      please try again in a few minutes.");
}

// If we're here, everything worked fine, so do your DB query and so on....

而不是die(),您可以使用您认为合适的内容:重新抛出另一个例外,将标头重定向到一般错误消息或任何您想要的内容。

7 - 这是更高级的,但您也可以这样做:创建自己的异常层次结构,如下所示:

class MVXException extends Exception {}
    class ExMVXDB extends MVXException {}
      class ExMVXDBRead extends ExMVXDB { }
      class ExMVXDBWrite extends ExMVXDB { }
      class ExMVXDBNotFound extends ExMVXDB { }

这是我在自制框架中的异常树的简化。这样做的好处是,如果您执行catch(ExMVXDB $e),您将捕获所有数据库错误。但是,如果您只想捕获数据写入操作,则可以执行catch(ExMVXDBWrite $e)

那就是它。错误处理并不简单,并且没有直接的答案,但有很多工具和良好实践可以帮助您选择最适合您的方法。

答案 2 :(得分:1)

1 - 您可以关闭display_errors并打开log_errors

@ini_set('log_errors','On');

@ini_set('display_errors','Off');

2 - 你可以使用默认的php Error和Logging功能&常数

请参阅:http://www.w3schools.com/php/php_ref_error.asp

3 - 您可以使用PHP Filesystem

实现自己的一组错误和日志记录功能

请参阅:http://www.w3schools.com/php/php_ref_filesystem.asp