Подтвердить что ты не робот

Регистрация ошибок, плавно

Я читал, в частности, "журнал ошибок". И я придумал функцию "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
}

Это пример того, о чем я говорил выше (не имея регистрации в классе/функции... Это хороший способ?)

Более того, каждый:

Я не совсем уверен, как использовать Исключения вообще. Скажем, я хочу сделать INSERT для базы данных с SQL внутри метода, будет ли я использовать try/catch, а затем перестроить исключение, если это не сработает? Это считается хорошей практикой? Примеры пожалуйста.

4b9b3361

Ответ 1

Во-первых, я хотел бы поблагодарить вас за поиск стандартных методов ошибок в PHP. К сожалению, error_log имеет некоторые ограничения, как вы узнали.

Это длинный ответ, читайте дальше, чтобы узнать о:

  • Ошибки
    • Запись ошибки напрямую vs trigger_error и set_error_handler
    • Где хорошие ошибки идут плохо - Fatal Errors.
  • Исключения
    • SPL
    • Что с ними делать?
  • Код
    • Настройка
    • Использование

TL; DR Используйте trigger_error для повышения ошибок и set_error_handler для их регистрации.

1. Ошибки

Когда в вашей программе все не так, как ожидалось, вы часто захотите поднять ошибку, чтобы кто-то или что-то было уведомлено. Ошибка в ситуации, когда программа может продолжаться, но произошло что-то примечательное, возможно, опасное или ошибочное. На этом этапе многие люди хотят немедленно регистрировать ошибку с помощью своего пакета ведения журнала. Я считаю, что это не то, что нужно делать. Я рекомендую использовать trigger_error, чтобы поднять ошибку, чтобы ее можно было обработать с помощью обратного вызова, установленного set_error_handler. Давайте сравним эти параметры:

Прямая запись ошибки

Итак, вы выбрали свой регистрационный пакет. Теперь вы готовы распространять вызовы на ваш регистратор везде, где возникает ошибка в коде. Давайте рассмотрим один вызов, который вы можете сделать (я буду использовать аналогичный регистратор для ответа в ответ Джека):

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

Что вам нужно для запуска этого кода?

    Class:  Logger
    Method: getLogger
    Return: Object with method 'error'

Это зависимости, которые необходимы для использования этого кода. Каждый, кто хочет повторно использовать этот код, должен будет предоставить эти зависимости. Это означает, что стандартной конфигурации PHP больше не будет достаточно для повторного использования вашего кода. В лучшем случае, используя Dependency Injection, вам по-прежнему требуется, чтобы объект журнала был передан во весь ваш код, который может испускать ошибку.

Кроме того, помимо того, что отвечает код, он также несет ответственность за регистрацию ошибки. Это противоречит принципу единой ответственности.

Мы видим, что запись ошибки напрямую плоха.

trigger_error для спасения

PHP имеет функцию trigger_error, которая может использоваться для повышения ошибки, как это делают стандартные функции. Уровни ошибок, которые вы используете с ним, определены в константах уровня . В качестве пользователя вы должны использовать одну из пользовательских ошибок: E_USER_ERROR, E_USER_WARNING или значение по умолчанию E_USER_NOTICE (другие уровни ошибок зарезервированы для стандартных функций и т.д.). Использование стандартной функции PHP для повышения ошибки позволяет повторить использование кода с любой стандартной установкой PHP! Наш код больше не отвечает за регистрацию ошибки (только убедитесь, что она поднята).

Используя trigger_error, мы выполняем только половину процесса регистрации ошибок (повышение ошибки) и сохраняем ответственность за ответ на ошибку для обработчика ошибок, который будет рассмотрен далее.

Обработчик ошибок

Мы устанавливаем собственный обработчик ошибок с помощью функции set_error_handler (см. настройку кода). Этот настраиваемый обработчик ошибок заменяет стандартный обработчик ошибок PHP, который обычно регистрирует сообщения в журнале ошибок веб-сервера в зависимости от настроек конфигурации PHP. Мы все еще можем использовать этот стандартный обработчик ошибок, возвращая false внутри нашего настраиваемого обработчика ошибок.

У пользовательского обработчика ошибок есть одна ответственность: реагировать на ошибку (включая любые записи, которые вы хотите сделать). Внутри настраиваемого обработчика ошибок у вас есть полный доступ к системе и вы можете запускать любой вид ведения журнала, который вы хотите. Практически любой регистратор, использующий шаблон проектирования Observer, будет в порядке (я не буду вдаваться в это, поскольку я считаю, что он имеет второстепенное значение). Это должно позволить вам подключаться к новым наблюдателям журнала для отправки вывода туда, где вам это нужно.

У вас есть полный контроль над тем, что вам нравится с ошибками в одной поддерживаемой части вашего кода. Теперь журнал ошибок можно быстро и легко изменить из проекта в проект или в рамках одного проекта со страницы на страницу. Интересно, что даже подавленные ошибки @ приводят к настраиваемому обработчику ошибок с errno of 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 разбираться с выключением. Однако эта функция выполняется всякий раз, когда завершается script (успешное, а также неудачное). Используя эту функцию и error_get_last, можно зарегистрировать некоторую базовую информацию (система почти завершена в этот момент), когда последняя ошибка была фатальной ошибкой. Также может быть полезно отправить правильный код состояния и отобразить страницу типа ошибки внутреннего сервера по вашему выбору.

2. Исключения

Исключения могут быть рассмотрены очень похожими на основные ошибки. Вместо trigger_error исключение будет генерироваться вашим кодом (вручную с помощью throw new Exception или из стандартного вызова функции). Используйте set_exception_handler, чтобы определить обратный вызов, который вы хотите использовать для обработки исключения.

SPL

Стандартная библиотека 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 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 Fixable:

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.

Ответ 2

Было предложено сделать этот ответ более применимым для более широкой аудитории, поэтому здесь идет.

Преамбула

Обработка ошибок обычно не первая вещь, о которой вы хотите подумать при написании приложения; как косвенный результат, он возникает при необходимости. Тем не менее, это не должно дорого стоить, чтобы использовать существующие механизмы в PHP.

Это довольно длинная статья, поэтому я разбил ее на логические наборы текста.

Ошибки запуска

В PHP существует два разных способа получения ошибок:

  • Ошибки самого PHP (например, с использованием переменных undefined) или внутренних функций (например, imagecreatefromjpeg невозможно открыть файл),
  • Ошибки, вызванные кодом пользователя, используя trigger_error,

Обычно они печатаются на вашей странице (если display_errors не выключен или error_reporting равно нулю), который должен быть стандартным для производственных машин, если вы не напишете идеальный код, как я... движется дальше); эти ошибки также могут быть захвачены, что дает вам возможность заглянуть в любой код в коде, используя set_error_handler ниже.

Отбрасывание исключений

Исключения отличаются от ошибок тремя основными способами:

  • Код, который их обрабатывает, может быть удален от места, из которого они выбраны. Состояние переменной в начале координат должно быть явно передано в конструктор Exception, иначе у вас будет только трассировка стека.
  • Код между исключением и уловкой полностью пропущен, тогда как после возникновения ошибки (и она не была фатальной) код все равно продолжается.
  • Они могут быть расширены из основного класса 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');

Для ударов вы можете превратить все ошибки в ErrorException, зарегистрировав следующий обработчик ошибок (PHP >= 5.1):

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. Есть и другие, но это иллюстрирует важность гибкого механизма ведения журнала.

Он использует следующие понятия:

  • Loggers - именованные объекты, которые выполняют регистрацию от вашего имени; они могут быть конкретными для класса в вашем проекте или использоваться как общий журнал,
  • Appenders - каждый запрос журнала может быть отправлен одному или нескольким адресатам (электронной почте, базе данных, текстовому файлу) на основе предопределенных условий (таких как уровень журнала)
  • Уровни - журналы классифицируются по сообщениям отладки на фатальные ошибки.

Основное использование для иллюстрации различных уровней сообщений:

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');

Используя эти концепции, вы можете смоделировать довольно мощное средство ведения журнала; например, без изменения кода, вы можете реализовать следующую настройку:

  • Соберите все отладочные сообщения в базе данных для разработчиков, чтобы посмотреть; вы можете отключить это на рабочем сервере,
  • Соберите предупреждения в ежедневный файл, который вы можете отправить по электронной почте в конце дня,
  • Имейте немедленные письма, отправленные по фатальным ошибкам.

Ответ 3

Определите его, затем используйте его:)

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

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

В качестве альтернативы просто добавьте третий параметр error_log по желанию, по умолчанию, по желанию.

Ответ 4

Если вам по-прежнему нужен собственный способ обработки журналов (т.е. вы не хотите использовать стандартный trigger_error()), я бы рекомендовал посмотреть на Zend_Log (http://framework.zend.com/manual/en/zend.log.overview.html) по следующим причинам:

  • это может использоваться как автономный компонент, 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);
    
  • Вам предложили множество журнальных библиотек, но я считаю, что команда Zend (основатели PHP lang) знают, что они делают

  • Вы можете использовать любые авторы (база данных, STDOUT - см. выше, файл, независимо от того, вы можете настроить его, чтобы писать свои собственные, чтобы отправлять сообщения журнала на веб-службу даже)
  • уровни журнала
  • может изменить формат журнала (но тот, который является готовым к работе, хорош для меня). Вышеприведенный пример со стандартным форматированием даст следующее:

    2012-05-07T23: 57: 23 + 03: 00 INFO (6): Информационное сообщение

  • просто прочитайте ссылку, она может быть настроена на обнаружение ошибок php.

Ответ 5

В качестве дополнения, для регистрации ошибок (и, фактически, для всего журнала) я использовал бы диспетчер событий, как это делает инфраструктура 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: Рассматривайте фрагменты кода как псевдокод, я их не тестировал. Подробности можно найти в документах указанных библиотек.

Ответ 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 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, потому что у вас есть другая логика для сортировки, все остальные ошибки выпадают, хотя и для первого catch, и обрабатываются верхним уловком, потому что все заброшенные исключения должны в какой-то момент их иерархия наследуется от Exception.

Очевидно, что если вы снова выбросите Exception (вне начального try {} или в верхней части catch {}), ваш script завершит работу с ошибкой "Невыключить исключение" и будет потерян журнал ошибок.

Если вы хотите пройти весь путь, вы также можете реализовать пользовательскую функцию обработки ошибок, используя set_error_handler(), и также разместите свой журнал.

Ответ 8

Есть две проблемы для встречи. Первое заключается в гибкости при регистрации в разных каналах. В этом случае вы должны взглянуть, например, на Monolog.

Вторая задача состоит в том, чтобы сплести при входе в ваше приложение. Imho лучшим случаем является не использование журналирования явно. Здесь, например, аспектная ориентация. Хороший образец flow3.

Но это больше похоже на птичий взгляд на проблему...

Ответ 9

Я использую свою собственную функцию, которая позволяет мне писать несколько типов файлов журнала, задавая или изменяя второй параметр.

Я прохожу мимо концептуальных вопросов, которые вы задаете, "чтобы сделать правильный путь", включив функцию журнала в библиотеку функций, которые я считаю "родными" для моих проектов разработки. Таким образом, я могу рассматривать эти функции как часть "MY" 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, является ошибкой заметок.

Ответ 11

Как заявляет KNL, что является совершенно правильным, но, к сожалению, пока еще недокументированным, наличие ошибок, исключающих исключения, не является чем-то, что рекомендовано разработчиками PHP, и кто-то ошибся в документации. Это может привести к ошибкам со многими расширениями, поэтому не делайте этого.

Это уже обсуждалось в #PHP на irc.

"Тем не менее, ошибки могут быть просто переведены на исключения с ErrorException". на http://php.net/manual/en/language.exceptions.php будет удален.