Шаблон проектирования для изящного сбоя, если отсутствует база данных - PullRequest
2 голосов
/ 05 марта 2012

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

Все мои классы, обращающиеся к базе данных, расширяют базовый класс, который предоставляет им доступ к базе данных, однако в конкретных классах есть некоторые методы, которые выполняют selects напрямую (т.е. не через методы базовых классов).

Если не включать каждый вызов базы данных в операторы if, как я могу изящно снизить функциональность, когда база данных недоступна?

EDIT

В случае изящного отказа для этого приложения будет отображаться сообщение «Служба недоступна» и прекращение попыток классов получить доступ к базе данных (что приведет к ошибкам).

Ответы [ 3 ]

3 голосов
/ 05 марта 2012

ИМХО, это подпадает под более широкую сферу общей обработки ошибок и исключений.

Некоторое введение ...

База данных по сути является входом глобальной переменной в вашем коде.Если он недоступен, это само определение неожиданного, «исключительного» состояния; должно привести к исключению.Конечно, вы явно спросили, как справиться с ситуацией «за исключением переноса каждого вызова базы данных в операторы if». Обтекание каждой операции БД в блоке try/catch в основном аналогично обертыванию каждой операции вif операторов.

Кроме того, функция mysql_connect вызовет ошибку PHP в дополнение к возвращению FALSE, если она не может подключиться.Вы действительно должны использовать PDO вместо динозавра mysql, но это совсем другая тема.Надеюсь, вы не используете оператор подавления ошибок @ или не сообщаете об ошибках E_WARNING, чтобы избежать этого.

Так как с этим справиться ...

Лично у меня ничего не будетделать с обработкой ошибок в PHP.Вы должны определить пользовательскую функцию-обработчик ошибок, используя set_error_handler документы , которая выдает исключение при любой ошибке PHP и обрабатывает исключения вместо ошибок .

Когда вы настраиваете свою стратегию обработки ошибок таким образом, тогда просто обернуть любую функциональность, которая может вызвать проблемы или неожиданно добавить блок try и обработать неожиданные события в ваших catch блоках..

Поскольку вы заявили, что «Все [ваши] обращенные к базе данных классы расширяют базовый класс, который предоставляет им доступ к базе данных», Я бы предложил добавить простое логическое свойство к базекласс, действующий в качестве флага для определения того, было ли сбой соединения с базой данных.Затем просто проверяйте значение флага перед каждой попыткой запроса к базе данных.Если вы правильно передаете экземпляр базы данных в ваших классах (и не прерываете ссылки), все они будут иметь доступ к одному и тому же свойству, когда им это потребуется.

Если соединение с базой данных не удалось, вы простоустановите гипотетический флаг $dbConn->connError = TRUE; в блоке try.

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

1 голос
/ 05 марта 2012

Возможна ли АОП?Это может позволить вам написать код, который перехватывает любую часть кода, которая соединяется с БД, и вставить ваш код обработки ошибок.

http://code.google.com/p/php-aop/

0 голосов
/ 06 марта 2012

Я не думаю, что моё решение в проекте легко сделать, но я делаю это так:

Когда я хочу, чтобы сбой был признан критическим в моем приложении, я использую исключения. В моем обработчике ошибок есть некоторая логика, которая определяет, соответствует ли исключения код http-статуса, например 4xx, если не генерируется общий код состояния 500.

Некритические сбои фиксируются менее разрушительным механизмом, использующим пользовательский класс результатов. Его базовая структура похожа на Исключение в том, что code и message передаются как аргументы конструктора. Кроме того, объект-результат может быть передан в качестве необязательного аргумента.

Result-класс выглядит так:

class Result
{
    /**
     * @var int
     */
    protected $resultCode;

    /**
     * @var string
     */
    protected $resultMessage;

    /**
     * @var mixed
     */
    protected $resultObject;

    /**
     * Inject object values on construction.
     *
     * @param int $code
     * @param string $message
     * @param mixed $result
     */
    public function __construct($code = 0, $message = null, $result = null)
    {
        $this->resultCode = intval($code);
        $this->resultMessage = (string) $message;
        $this->resultObject = $result;
    }

    /**
     * Returns true when result is considered a success, determined by the
     * resultCode, otherwise false.
     *
     * @return bool
     */
    public function isSuccess()
    {
        if ($this->resultCode > 0) {
            return true;
        }
        return false;
    }


    /**
     * Returns true when result is considered an error, determined by the
     * resultCode, otherwise false.
     *
     * @return bool
     */
    public function isError()
    {
        if ($this->resultCode < 1) {
            return true;
        }
        return false;
    }

    /**
     * Returns the result message.
     *
     * @return string
     */
    public function getMessage()
    {
        return $this->resultMessage;
    }

    /**
     * Returns the actual result object.
     *
     * @return mixed
     */
    public function getResult()
    {
        return $this->resultObject;
    }
}

Требуется только код результата. Результат считается успешным, если код> 0, в противном случае он считается ошибкой. Объект результата может быть фактическим результатом (если он успешен), например, строка или набор строк из запроса или (если ошибка) ввода или частей ввода, которые имеют отношение, например, идентификатор строки, которую вы искали.

Поскольку этот класс результатов не вызывает errorHandler, MVC-приложению доверяют для обработки ошибок. либо с помощью исключения, либо изящно реагируя на результат ошибки, показывая сообщение или что-то еще, что было передано как объект результата.

Если я передам этот результат своему представлению, я могу реагировать, является ли $result->isSuccess() истинным или ложным, и просто получить фактический результат с помощью $result->getResult() или отобразить сообщение об ошибке с помощью $result->getMessage().

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