【问题标题】:Error logging, in a smooth way以流畅的方式记录错误
【发布时间】:2012-05-07 01:08:56
【问题描述】:

我一直在阅读特别是“错误日志”的内容,并且我提出了“error_log”函数,它似乎是用于处理错误日志的好工具。但是如何最流畅最好的使用呢?

如果我有一个

try {
     //try a database connection...

} catch (PDOException $e) {
    error_log($e->getMessage(), 3, "/var/tmp/my-errors.log");

}

这会将错误记录在 my-errors.log 文件中。但是如果我有时需要更改文件的位置、新文件夹或其他东西的位置怎么办。如果我有大量文件,我需要全部更改。

现在我开始考虑使用变量来设置错误日志的路径。当然可以,但是如果我想在函数或类方法中使用 error_log 怎么办?然后我需要将变量设置为全局变量,但这被认为是不好的做法!但是如果我不应该在一个类的深处使用这个函数,那不也被认为是不好的做法吗?这里有什么好的解决方案?

<?php

function legit() {
    try {
        if (1 == 1) {
            throw new Exception('There was an error here');
        }
    } catch (Exception $e) {
        throw new Exception('throw the error to the try-catch outside the function...');
    }

}

try {
    legit();
} catch (Exception $e) {
    echo 'error here' . $e->getMessage();

    //log it
}

这是我上面所说的一个例子(没有在类/函数中深入记录日志......这是一个好方法吗?)

弗塞隆:

我不太确定我应该如何使用一般的例外。假设我想在方法中使用 SQL 对数据库执行 INSERT,我会使用 try/catch,然后在失败时重新抛出异常吗?这被认为是好的做法吗?请举例。

【问题讨论】:

  • 您是否考虑过使用内置错误日志记录、使用log_errors 配置指令以及可选的trigger_error 将它们发送到日志?这会将它们发送到您的 Web 服务器的错误日志。而且您不必手动操作。
  • 嗯,根据情况,我想使用不同的日志记录、电子邮件、数据库等方法。

标签: php pdo


【解决方案1】:

首先,我想赞扬您查看 PHP 中的标准错误方法。不幸的是,您发现error_log 有一些限制。

这是一个很长的答案,请继续阅读以了解:

  1. 错误
    • 直接记录错误与trigger_errorset_error_handler
    • 好的错误变坏的地方 - 致命错误。
  2. 例外情况
    • 声压级
    • 如何处理它们?
  3. 代码
    • 设置
    • 用法

TL;DR 使用trigger_error 引发错误,使用set_error_handler 记录错误。

1。错误

当您的程序没有按预期进行时,您通常会希望引发错误以便通知某人或某事。错误是指程序可能继续运行,但发生了值得注意的、可能有害或错误的情况。此时,许多人希望使用他们选择的日志记录包立即记录错误。我相信这是完全错误的做法。我建议使用trigger_error 来引发错误,以便可以使用set_error_handler 设置的回调来处理它。让我们比较一下这些选项:

直接记录错误

所以,您已经选择了您的日志记录包。现在,您可以在代码中出现错误的任何地方将调用传播到您的记录器。让我们看一下您可能拨打的单个电话(我将使用与 Jack 回答中的记录类似的记录器):

Logger::getLogger('standard')-&gt;error('Ouch, this hurts');

运行此代码需要什么?

:记录器 方法:getLogger 返回:方法为“错误”的对象

这些是使用此代码所需的依赖项。每个想要重用此代码的人都必须提供这些依赖项。这意味着标准的 PHP 配置将不再足以重用您的代码。在最好的情况下,使用依赖注入,您仍然需要将一个记录器对象传递到所有可能发出错误的代码中。

此外,除了代码负责的任何事情之外,它还负责记录错误。这违反了Single Responsibility Principle

我们可以看到直接记录错误是不好的

trigger_error 救援

PHP 有一个名为trigger_error 的函数,它可以像标准函数一样用于引发错误。与它一起使用的错误级别在error level constants 中定义。作为用户,您必须使用以下用户错误之一:E_USER_ERRORE_USER_WARNING 或默认值 E_USER_NOTICE(其他错误级别保留用于标准功能等)。使用标准 PHP 函数来引发错误允许代码在任何标准 PHP 安装中重复使用!我们的代码不再负责记录错误(仅确保引发错误)。

使用trigger_error,我们只执行了一半的错误记录过程(引发错误),并将响应错误的责任留给了错误处理程序,这将在接下来介绍。

错误处理程序

我们使用set_error_handler 函数设置了一个自定义错误处理程序(参见代码设置)。此自定义错误处理程序取代了标准 PHP 错误处理程序,后者通常根据 PHP 配置设置在 Web 服务器错误日志中记录消息。我们仍然可以通过在自定义错误处理程序中返回 false 来使用这个标准错误处理程序。

自定义错误处理程序只有一个职责:响应错误(包括您想要执行的任何日志记录)。在自定义错误处理程序中,您可以完全访问系统,并且可以运行您想要的任何类型的日志记录。几乎任何使用观察者设计模式的记录器都可以(我不打算深入讨论,因为我认为它是次要的)。这应该允许您挂接新的日志观察者以将输出发送到您需要的地方。

您可以完全控制在代码的单个可维护部分中对错误执行您喜欢的操作。现在可以在项目之间或在单个项目中从页面到页面快速轻松地更改错误记录。有趣的是,即使 @ 被抑制的错误也会以 errno 为 0 的方式进入自定义错误处理程序,如果尊重 error_reporting 掩码,则不应报告。

当好的错误变坏时 - 致命错误

无法从某些错误继续。自定义错误处理程序无法处理以下错误级别:E_ERRORE_PARSEE_CORE_ERRORE_CORE_WARNINGE_COMPILE_ERRORE_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 定义您要用来处理异常的回调。

声压级

标准 PHP 库 (SPL) 提供 exceptions。它们是我引发异常的首选方式,因为就像 trigger_error 一样,它们是 PHP 的标准部分,不会为您的代码引入额外的依赖项。

如何处理它们?

当抛出异常时,可以进行三种选择:

  1. 抓住它并修复它(然后代码继续,好像没有发生任何不好的事情)。
  2. 抓住它,附加有用的信息并重新抛出它。
  3. 让它冒泡到更高的水平。

在堆栈的每一层都做出这些选择。最终,一旦它冒泡到最高级别,您使用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 追加:

观察下面code_that_can_generate_exception() 是如何不知道$context 的。这个级别的 catch 块有更多信息,如果它有用,可以通过重新抛出它来附加到异常中。

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.

【讨论】:

  • 感谢一个很好的帖子,其实我前一阵子找到了set_error_handler,但这让话题更清晰了。关于异常你会怎么做?我应该在一个类中的所有方法中捕获错误还是让更高级别的 set_exception_handler 修复它? :)
  • 只有当我能做一些有用的事情时,我才会抓住它。当你看到它时,你就会知道你可以做一些有用的事情的水平。如果你有疑问,让它冒泡。设置的异常处理程序将无法修复异常,但可能适用于您的代码无法正常工作的异常。例如:我希望数据库抛出异常和使用数据库捕获它们的方法(除了可能由 set_exception_handler 处理的数据库连接失败)。不过,这确实取决于个人情况。
  • 虽然这个答案是在 2012 年写的,但我仍然觉得它非常有用。非常感谢你说得很清楚@paul
  • @Paul 很好的答案!
【解决方案2】:

已要求使此答案更适用于更多受众,所以就这样吧。

序言

错误处理通常不是您在编写应用程序时首先要考虑的事情。作为间接结果,它会在需要时得到加强。但是,利用 PHP 中的现有机制也不必花费太多。

这是一篇相当长的文章,所以我将其分解为符合逻辑的文本集。

触发错误

在 PHP 中有两种不同的触发错误的方式:

  1. PHP 本身的错误(例如使用未定义的变量)或内部函数(例如imagecreatefromjpeg 无法打开文件),
  2. 用户代码使用trigger_error触发的错误,

这些通常打印在您的页面上(除非display_errors 已关闭或error_reporting 为零),这应该是生产机器的标准,除非您像我一样编写完美的代码......继续);这些错误也可以被捕获,通过使用set_error_handler 稍后解释,让您了解代码中的任何问题。

抛出异常

异常在三个主要方面不同于错误:

  1. 处理它们的代码可能远离它们被抛出的地方。源头的变量 state 必须显式传递给 Exception 构造函数,否则您只有堆栈跟踪。
  2. 异常和捕获之间的代码被完全跳过,而在发生错误(并且不是致命的)之后代码仍然继续。
  3. 它们可以从主Exception类扩展;这允许您捕获和处理特定异常,但让其他人在堆栈中冒泡,直到它们被其他代码捕获。另请参阅:http://www.php.net/manual/en/language.exceptions.php

后面会给出一个抛出异常的例子。

处理错误

通过注册错误处理程序来捕获和处理错误非常简单,例如:

function my_error_handler($errno, $errstr, $errfile = 'unknown', $errline = 0, array $errcontext = array())
{
    // $errcontext is very powerful, it gives you the variable state at the point of error; this can be a pretty big variable in certain cases, but it may be extremely valuable for debugging
    // if error_reporting() returns 0, it means the error control operator was used (@)
    printf("%s [%d] occurred in %s:%d\n%s\n", $errstr, $errno, $errfile, $errline, print_r($errcontext, true));

    // if necessary, you can retrieve the stack trace that led up to the error by calling debug_backtrace()

    // if you return false here, the standard PHP error reporting is performed
}

set_error_handler('my_error_handler');

为了好玩,您还可以通过注册以下错误处理程序 (PHP >= 5.1) 将所有错误转换为 ErrorException

function exception_error_handler($errno, $errstr, $errfile, $errline)
{
    throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}

set_error_handler("exception_error_handler");

处理异常

在大多数情况下,您处理的异常尽可能接近导致它允许备份计划的代码。例如,您尝试插入数据库记录并抛出主键约束异常;您可以通过更新记录来恢复(设计为大多数数据库可以自己处理)。有些异常无法在本地处理,因此您希望将它们级联。示例:

function insertRecord($user, $name)
{
    try {
        if (true) {
            throw new Exception('This exception should not be handled here');
        }
        // this code is not executed
        $this->db->insert('users', array('uid' => $user, 'name' => $name));
    } catch (PDOException $e) {
        // attempt to fix; an exception thrown here will cascade down
        throw $e; // rethrow exception

        // since PHP 5.3.0 you can also nest exceptions
        throw new Exception("Could not insert '$name'", -1, $e);
    } catch (WhatEverException $e) {
        // guess what, we can handle whatever too
    }
}

滑溜溜的例外

那么当你在任何地方都没有捕捉到异常时会发生什么?你也可以使用set_exception_handler 来捕捉它。

function my_exception_handler(Exception $exception)
{
    // do your stuff here, just don't throw another exception here
}

set_exception_handler('my_exception_handler');

除非您没有有意义的方法来处理代码中任何地方的异常,否则不鼓励这样做。

记录错误/异常

现在您正在处理错误,您必须将其记录在某个地方。在我的示例中,我使用了一个 Apache 从 Java 移植到 PHP 的项目,名为 LOG4PHP。还有其他的,但它说明了灵活的日志记录工具的重要性。

它使用以下概念:

  1. Loggers - 代表您执行登录的命名实体;它们可以特定于您项目中的某个类,也可以作为通用记录器共享,
  2. Appenders - 每个日志请求都可以根据预定义的条件(例如日志级别)发送到一个或多个目的地(电子邮件、数据库、文本文件),
  3. 级别 - 日志从调试消息到致命错误分类。

说明不同消息级别的基本用法:

Logger::getLogger('main')->info('We have lift off');
Logger::getLogger('main')->warn('Rocket is a bit hot');
Logger::getLogger('main')->error('Houston, we have a problem');

使用这些概念,您可以建模一个非常强大的日志记录工具;例如,在不改变上述代码的情况下,您可以实现以下设置:

  1. 收集数据库中的所有调试消息供开发人员查看;您可以在生产服务器上禁用此功能,
  2. 将警告收集到每日文件中,您可以在一天结束时通过电子邮件发送,
  3. 立即发送有关致命错误的电子邮件。

【讨论】:

  • 哈哈哈不错的休斯顿参考:P
  • @Jack 非常完整的答案。在错误处理的同一主题上(尽管在 c++ 中),您将我的一个问题关闭为“含糊不清”,而没有任何解释或指示来帮助或礼貌地说明如何减少对您和您的冒犯。我已对其进行了编辑并请求您的支持对其进行审查(如果您关闭它,您应该是第一个分析它现在是否可以的人)。非常感谢您的支持。 ps:非常酷的产品,你的muvee,我会在不久的将来与你联系! stackoverflow.com/questions/12609104/catch-mysql-error-in-c
【解决方案3】:

定义它,然后使用它:)

define('ERRORLOG_PATH', '/var/tmp/my-errors.log');

error_log($e->getMessage(), 3, ERRORLOG_PATH);

或者,只需将error_log 的第三个参数设为可选,默认为您想要的路径。

【讨论】:

    【解决方案4】:

    另外,对于错误日志(实际上是所有日志),我会使用事件调度器,就像 symfony 框架那样。

    看看这个sf组件(它的依赖非常轻量级,不需要整个框架,可能有3个相关的php类和2个接口)

    https://github.com/symfony/EventDispatcher

    这样您就可以在应用程序引导程序的某处创建调度程序:

    use Symfony\Component\EventDispatcher\EventDispatcher;
    use Symfony\Component\EventDispatcher\Event;
    
    $dispatcher = new EventDispatcher();
    
    //register listeners
    $dispatcher->addListener('application.log', function (Event $event) {
        //do anything you want
    });
    

    然后你可以在代码的任何地方引发一个事件,比如

    $dispatcher->dispatch(new GenericEvent('application.log', array('message' => 'some log', 'priority' => 'high'));
    

    当然你可以用你自己的事件子类化事件类:

    class LogEvent extends GenericEvent {
        public function __construct($message, $priority = 'INFO') {
            parent::__construct('application.log', array('message'=>$message,'priority'=>$priority));
        }
        public function getMessage() { return $this->getArgument('message'); }
        public function getPriority() { return $this->getArgument('priority'); }
    }
    
    // now raising LogEvent is much cleaner:
    $dispatcher->dispatch(new LogEvent('some log'));
    

    这也将允许您创建更多自定义事件,例如 ExceptionEvent

     class ExceptionEvent extends GenericEvent {
        public function __construct(Exception $cause) {
            parent::__construct('exception.event', array('cause' => $cause));
        }
     }
    

    并相应地处理它们。

    优势

    • 您将日志记录逻辑与应用程序分开
    • 您可以在运行时轻松添加和删除记录器
    • 您可以轻松注册任意数量的记录器(即 DebugLogger 将所有内容记录到文本文件中,ErrorLogger 仅将错误记录到 error_log,CriticalLogger 仅记录生产环境中的严重错误并通过电子邮件发送给管理员等)
    • 您可以将事件调度程序用于更多的事情,而不仅仅是记录(实际上对于适合观察者模式的每个作业)
    • 实际的记录器只不过是“实现细节”——它很容易替换,以至于你的日志去哪里都没有关系——你可以随时替换日志目的地,而不必重构你的方法名称,或更改代码中的任何内容。
    • 将很容易实现复杂的日志路由逻辑或全局更改日志格式(通过配置记录器)
    • 如果您为侦听器(记录器)和调度器(通知日志事件的类)使用依赖注入,一切都会变得更加灵活

    实际记录

    正如有人已经说过的,我建议使用开箱即用的库,比如提到的 Monolog、Zend_Log 或 log4php,可能没有理由手动编写这些东西(你最不想要的是错误记录器损坏!)

    PS:将代码 sn-ps 视为伪代码,我没有测试它们。详细信息可以在上述库的文档中找到。

    【讨论】:

      【解决方案5】:

      如果您仍需要自定义的日志处理方式(即您不想使用标准的trigger_error()),我建议您查看 Zend_Log (http://framework.zend.com/manual/en/zend.log.overview.html),原因如下:

      1. 这可以作为一个独立的组件使用,ZF 不是一个全栈框架。你可以只复制 Zend_Loader 和 Zend_Log 命名空间,实例化 Zend_Loader 并使用它。见下文:

        require_once('Zend/Loader/Autoloader.php');
        
        $loader = Zend_Loader_Autoloader::getInstance();
        
        $logger = new Zend_Log();    
        $writer = new Zend_Log_Writer_Stream('php://output');
        
        $logger->addWriter($writer);    
        $logger->log('Informational message', Zend_Log::INFO);
        
      2. 为您提供了许多日志库,但我相信 Zend 团队(PHP 语言的创始人)知道他们在做什么

      3. 您可以使用任何编写器(数据库、STDOUT - 见上文、文件等,您可以自定义它以编写自己的编写器以将日志消息发布到 Web 服务)
      4. 日志级别
      5. 可能会更改日志格式(但我认为开箱即用的格式很棒)。上面带有标准格式化程序的示例将产生如下内容:

      2012-05-07T23:57:23+03:00 INFO (6):信息性消息

      1. 只是阅读参考,它可能配置为捕获 php 错误

      【讨论】:

      • 我在其他项目中使用过 Zend_log,出于某种原因我对此并不满意,但还是感谢您的回复
      • @John:还有 monologapache log4php - 可能这很有帮助。
      【解决方案6】:

      如果 PHP 处理错误的方式对您来说不够灵活(例如,有时您想记录到数据库,有时记录到文件,有时是其他任何东西),您需要使用/创建自定义 PHP 记录框架。

      您可以浏览https://stackoverflow.com/questions/341154/php-logging-framework 中的讨论,或者直接选择首选KLogger,试试看。不过,我不确定它是否支持自定义日志记录目标。但至少,它是一个小而易读的类,您应该能够根据自己的需要进一步扩展它。

      【讨论】:

        【解决方案7】:

        我会选择 Tom vand der Woerdt 的日志记录解决方案,它最简单、最有效地满足您的要求。

        关于另一个问题:

        除非有特定类型的异常您有解决方案,否则您不需要在函数内捕获/重新抛出异常。

        有点简单的例子:

        define('ERRORLOG_PATH', '/var/tmp/my-errors.log');
        function do_something($in)
        {
            if (is_good($in))
            {
                try {
                    return get_data($in);
                } catch (NoDataException $e) {
                    // Since it's not too big a deal that nothing
                    // was found, we just return false.
                    return false;
                }
            } else {
                throw new InvalidArguementException('$in is not good');
            }
        }
        
        function get_data($data)
        {
            if (!is_int($data))
            {
                InvalidArguementException('No');
            }
            $get = //do some getting.
            if (!$get)
            {
                throw new NoDataException('No data was found.');
            } else {
                return $get;
            }
        }
        
        try {
           do_something('value');
        } catch (Exception $e) {
           error_log($e->getMessage(), 3, ERRORLOG_PATH);
           die ('Something went wrong :(');
        }
        

        在这里你只能捕获NoDataException,因为你有一些其他的逻辑来解决它,所有其他错误都属于第一个捕获并由顶部捕获处理,因为所有抛出的异常都必须在它们的某个时间点层次结构继承自Exception

        显然,如果您再次抛出 Exception(在初始 try {} 或顶部 catch {} 之外),您的脚本将退出并出现未捕获异常错误并且错误日志记录会丢失。

        如果您想一路走下去,您还可以使用set_error_handler() 实现自定义错误处理功能并将您的登录也放在那里。

        【讨论】:

          【解决方案8】:

          要应对两个挑战。首先是灵活地登录到不同的频道。在这种情况下,您应该查看例如Monolog

          第二个挑战是将登录信息融入到您的应用程序中。恕我直言,最好的情况是不明确使用日志记录。例如aspect orientation 就派上用场了。一个好的示例是flow3

          但这更多的是对问题的鸟瞰......

          【讨论】:

            【解决方案9】:

            我使用我自己的函数,它允许我通过设置或更改第二个参数来编写多种类型的日志文件。

            通过将 log 函数包含在我认为对我的开发项目“原生”的函数库中,我解决了您提出的关于“什么是正确的方法”的概念性问题。 这样我就可以认为这些函数只是“我的”php核心的一部分,比如date()time()

            在这个基本版本的 dlog 中,我还处理数组。虽然我最初使用它来记录错误,但我最终将它用于其他“快速而肮脏”的短期跟踪,例如记录代码进入某个部分的时间,以及用户登录等。

            function dlog($message,$type="php-dlog")
            {
                if(!is_array($message)  )
                    $message=trim($message);
                error_log(date("m/d/Y h:i:s").":".print_r($message,true)."\n",3, "/data/web/logs/$_SERVER[HTTP_HOST]-$type.log");
            } 
            

            【讨论】:

              【解决方案10】:

              大多数错误记录器和异常记录器对大多数人来说都是无用的,因为它们无法访问日志文件。

              如果系统在数据库上运行,我更喜欢使用自定义错误处理程序和自定义异常处理程序,并让它们在生产期间将错误直接记录到数据库中。

              在开发过程中,当设置了 display_errors 时,它们不会记录任何内容,因为所有错误都会在浏览器中引发。

              附带说明:不要让您的自定义错误处理程序抛出异常!这真是个坏主意。它可能会导致缓冲区处理程序和某些扩展出现错误。还有一些核心 PHP 函数,如 fopen() 会在失败时发出警告或通知,这些应该相应地处理,并且不应该停止应用程序有异常会做。

              在 PHP 文档中提到让错误处理程序抛出异常是一个注释错误。

              【讨论】:

              • 1.我对“大多数人”的说法表示怀疑。 2. 无论如何,您可以随时告诉 PHP 将日志写入您想要的任何文件。 3. 数据库本身容易出错,因此错误日志的存储不可靠。 4. 你处理异常的想法是完全错误的。它的异常可以被捕获而不是停止脚本,而错误没有这样的机制。一般来说,自定义处理是一个好主意,但你的实现和推理是没有问题的。
              • 文件记录在很大程度上依赖于用户对主机的写入权限和对这些文件的访问。是的,虽然数据库可能出现故障,但它仍然是记录错误和异常的最简单的地方之一,您可以轻松地验证您对数据库的访问。根据您的推理,我们应该使用数据库,而大多数 PHP Web 应用程序高度依赖数据库并对其进行访问,因此如果应用程序正在使用数据库,那么登录到它也很有意义。关于抛出异常的错误,你不知道你在说什么。就像我说的,它可能会导致错误。
              • 根据我的推理,每种媒介都必须用于其目的。 无论如何,最重要的致命错误都会记录在错误日志中 - 因此,使用 2 种介质是没有意义的。对于这个关于异常的声明,我相信你有一个可以重现的证明代码。提前致谢。
              【解决方案11】:

              正如 KNL 所说,这是完全正确的,但不幸的是,到目前为止还没有记录,PHP 开发人员不建议出现抛出异常的错误,并且有人在文档中犯了错误。它确实会导致许多扩展出现错误,所以不要这样做。

              这已经在 irc 上的#PHP 上进行了辩论。

              “但是,错误可以通过 ErrorException 简单地转换为异常。” http://php.net/manual/en/language.exceptions.php 将被删除。

              【讨论】:

                猜你喜欢
                • 2011-09-27
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-09-03
                • 2010-10-23
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多