Логическая проблема с расширением исключений в php - PullRequest
0 голосов
/ 18 января 2020

С PHP Я использую следующую структуру классов для исключений:

class ProjectException extends Exception {
          ... logical code for handling exceptions, functions that are relevant to every exception my project throws go here
}

class SpecificException extends ProjectException {
     protected $codePrefix = 'SE';

     const ERROR_SOMETHING_BAD_HAPPENED              = 100;
     const ERROR_SOMETHING_SIMMILARLY_BAD_HAPPENED   = 101;

     /* no functions go in this class, this class is only to specify the code prefix of the exception, and the error codes used by it */
}

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

 try {
    /** try something here **/
 } catch (SpecificException $e) {
    switch ($e->getCode()) {
       case SpecificException::ERROR_SOMETHING_BAD_HAPPENED:
         /** react to the exception based on it's code, and try to recover **/
       default:
         /** react to every unexpected code, which may appear if the tried function is modified,
             and throws a new exception code of the same type, and stop the execution of the 
             script, storing the error in the database **/
    }
 }

Моя проблема в следующем. Я хотел бы «заблокировать» некоторые файлы от редактирования, например, некоторые файлы исключений. Почему я хочу сделать это, потому что я пытаюсь сделать часть своего кода переносимой, чтобы его можно было использовать в других проектах, над которыми мы также работаем.

Моя идея заключалась в том, что позже В новых проектах, если появится что-то новое и должен быть создан новый код исключения, я расширю «заблокированное» исключение и напишу новый код ошибки как const в расширяющем классе. Реальный сценарий, который может произойти, это класс Account. Чистый класс Account уже разработан в переносимом коде с функциями входа в систему и регистрации, но в каждом отдельном проекте эти учетные записи получат новые функции, определенные проектом c. Таким образом, в новом проекте я расширю класс переносимых проектов Account и напишу там связанные с ним функциональные возможности.

Теоретически это может сработать, но я понял, что управление этим позже будет реальным боль, я думаю, потому что:

  1. при перехвате исключений мне сейчас нужно либо перехватить родительское исключение, чтобы перехватить каждое выброшенное исключение, либо мне нужно написать два (три, четыре и т. д. * 1029). *.) отдельные блоки перехвата, в зависимости от того, сколько раз я расширил исходное родительское исключение
  2. если я перехватил родительское исключение, я не могу просто добавить все коды, не зная происхождение кода (родительский или дочерний класс)

По сути, я должен был бы написать блоки simmilar try catch для них:

try {
  /** some code to try **/
} catch (SpecificException $e) {
  /** this will catch everything that is SpecificException or SpecificExtendedException or SpecificDoubleExtendedException **/
  switch ($e->getCode()) {
      case SpecificException::ERROR_IN_SPECIFIC:
         /** do something **/
         break;
      case SpecificException::ERROR_TWO_IN_SPECIC:
         /** do something **/
         break;
      case SpecificDoubleExtendedException::ERROR_IN_SECOND_EXTENDED_EXCEPTION:
         /** do something **/
         break;
      default:
         /** as it was originally written **/
         break;
    } 
}

Кто-нибудь знает, как мне поступить? Каков наиболее естественный способ «заблокировать» некоторые переносимые файлы и добавить новые коды исключений в исключения, определенные в этих «заблокированных» файлах?

1 Ответ

1 голос
/ 18 января 2020

Вы можете просто добавить такой метод в свой класс ProjectException:

public function getCodeFor(string $name): int
{
  return (int)constant("static::ERROR_$name");
}

При этом используется вспомогательная функция constant вместе с static Ключевое слово для извлечения константы, определенной в фактическом классе объекта, для которого был вызван метод.

Тогда вы могли бы таким образом блокировать try блок, который работал бы для любого класса, расширяющего SpecificException :

switch ($e->getCode()) {
  case $e->getCodeFor('SOMETHING_BAD_HAPPENED'):
    /** do something **/
    break;
  case $e->getCodeFor('SOMETHING_SIMILARLY_BAD_HAPPENED'):
    /** do something **/
    break;
  case $e->getCodeFor('SOMETHING_SPECIFICALLY_BAD_HAPPENED'):
    /** do something **/
    break;
}

Демонстрация: https://3v4l.org/sAQdE

Примечание: очевидно, что использование строк приводит к потере возможности IDE-рефакторинга ваших констант. Но так как вы не можете заранее знать, какие классы будут определять данный код (или вы можете, но не хотели бы этого), то это разумный обходной путь.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...