Лучшая практика ведения журнала пользовательских исключений в PHP

У меня есть настраиваемое исключение (которое может быть расширено другими настраиваемыми исключениями). Мой проект требует регистрации всех возникающих customExceptions (и всех его потомков). У меня есть регистратор, который может регистрировать customException (и все остальное). Один из способов сделать это - явно регистрировать исключение всякий раз, когда оно обрабатывается следующим образом.

try{
    //some exception occur
}
catch(customeException $e)
{
     $log->logException($e);
     $e->showMessage(); // or do anything that we have to do with the error.
}

Поскольку мы регистрируем все customExceptions, другой способ, который я могу придумать, - обновить конструктор customException и зарегистрировать исключение прямо здесь, внутри конструктора. Таким образом, он гарантирует, что все customException зарегистрированы. Однако, если мы пойдем по этому пути, у меня возникнут следующие вопросы:

  1. Как вставить логгер в customException?
  2. Будет ли это противоречить принципу SRP?
  3. Будет ли это считаться плохой практикой в ​​смысле ООП или как это лучше всего?

person Md Monjur Ul Hasan    schedule 28.02.2018    source источник


Ответы (2)


Я думаю, что вводить регистратор в CustomException неправильно, потому что (как вы указали) он нарушает SRP и увеличивает сложность ваших классов исключений.

Я предлагаю вам отделить Exception от ExceptionHandler. Класс исключения должен содержать только информацию о том, «что (и где) пошло не так». ExceptionHandler отвечает за регистрацию исключения (и при необходимости выполняет другую работу с исключением).

Таким образом, вы можете настроить один глобальный ExceptionHandler (используя set_exception_handler и < href = "http://php.net/manual/en/function.set-error-handler.php" rel = "nofollow noreferrer"> set_error_handler или какой-либо механизм обработки исключений на основе инфраструктуры, например Symfony ExceptionListener), который перехватит все необработанные исключения.

<?php

class ExceptionHandler {
  /**
   * @var Logger
   */
  private $logger;

  public function __construct(Logger $logger)
  {
    $this->logger = $logger;
  }

  public function handle(Throwable $e)
  {
    $this->logger->logException($e);
  }
} 

В коде приложения вы по-прежнему можете генерировать и перехватывать исключения. Думаю, есть 4 типичных ситуации.

Полностью восстанавливаемые исключения

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

<?php

try {
  $methodThatThrowsException();
}
catch (DoesNotMatterException $e) {
  // do some stuff and continue the execution
  // note, that this exception won't be logged 
}

Исправляемое зарегистрированное исключение

То же, что и предыдущее, но вы хотите зарегистрировать это исключение.

<?php

try {
  $methodThatThrowsException();
}
catch (NonCriticalExceptionThatShouldBeLogged $e) {
  $this->exceptionHandler->handle($e); // log exception
  // do some stuff and continue the execution
}

Невосстановимые исключения с "финализатором"

Вы хотите выполнить определенную бизнес-логику, а затем потерпите неудачу. Вы можете перехватить исключение, обработать его и затем снова выбросить. Глобальный обработчик исключений обработает это исключение и зарегистрирует его.

<?php 

try {
  $methodThatThrowsException();
}
catch (CriticalException $e) {
  // do some stuff like cleanup/transaction rollback
  throw $e;
}    

Невосстановимые исключения

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

<?php

$methodThatThrowsException();

// ExceptionHandler::handle will be executed
person Ivan Kalita    schedule 01.03.2018

Сервисы могут быть добавлены в другие сервисы, если они актуальны и поддерживают SRP или делают что-то системное, например, ведение журнала ошибок. Однако исключение на самом деле не является службой, и оно должно быть связано только с управлением данными исключения, основанными на том, что они могут быть выброшены.

Я думаю, что регистрация в классе исключений также является проблемой из-за:

  1. Нет контроля над тем, какой тип журнала использовать, предупреждение, ошибка, критический и т. Д. Если вы не сделаете его запутанным / сложным
  2. Нет контроля над тем, регистрироваться или нет. Существуют сценарии, в которых может произойти исключение, но это известный сценарий, который не требует обработки ошибок и т. Д.
  3. Вам нужно будет передать различные другие данные журнала в исключение, что, возможно, немного пахнет в зависимости от данных, которые вы хотите зарегистрировать.

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

Когда вы доберетесь до вершины, например контроллер, не бросайте, а визуализируйте представление с красивым сообщением.

person James    schedule 08.10.2020