Как правильно написать свой обработчик ошибок php?

За обработку ошибок у меня в скрипте отвечает следующая функция:

function error_handler(
    $error_code,
    $error_message,
    $error_file_name,
    $error_line,
    $error_context
  ){

    echo 'Error_code: ' . $error_code . '<br />';
    echo 'Error_message: ' . $error_message . '<br />';
    echo 'Error_file_name: ' . $error_file_name . '<br />';
    echo 'Error_line: ' . $error_line . '<br />';

    // some code...

    die();

  }

  set_error_handler('error_handler');

Но есть моменты, которые мне не понятны. Например, в своём скрипте я использую метод транзакций:

// some code...

$host_db = '127.0.0.1';
$login_db = 'root';
$password_db = '';
$database_db = 'some_db';

$DB = new PDO('mysql:host=' . $host_db . ';dbname=' . $database_db, $login_db, $password_db);
$DB -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$DB -> beginTransaction();

// some code...

$DB -> commit();

// some code...

Если в скрипте произошла ошибка, то как мне откатить транзакцию в функции error_handler? Там ведь недоступна переменная $DB!!!

То же самое и с загрузкой файлов (скрипт приводить не буду). Все загруженные файлы я сохраняю в массив uploaded_files, как мне удалить все загруженные файлы, в случае возникновения ошибки, если переменная uploaded_files не видна в функции error_handler?

Как вообще правильно реализовывать обработку ошибок на php?

ДОПОЛНЕНИЕ:

Что делать если ошибка произойдёт в функции error_handler 0_0?
  • Вопрос задан
  • 347 просмотров
Решения вопроса 3
FanatPHP
@FanatPHP
Чебуратор тега РНР
Перед тем как писать обработчик, надо сначала понять, а зачем он нужен.
Потому что вот эта вот функция - она совершенно бессмысленная.
Вся "обработка", которой она занимается - это добавляет бессмысленные фразы типа "Error_message" к тому что РНР выведет и так.

Обработчик ошибок не должен заниматься удалением файлов. Обработчик вступает в дело, когда ничего исправить уже нельзя, и всё что остаётся - это показать пользователю страницу с извинениями и корректным НТТР кодом. Пример можно взять здесь: https://phpdelusions.net/articles/error_reporting

А вот обрабатывать ошибки надо с помощью оператора try catch
Если надо откатить транзакцию, то всю её целиком надо поместить внутрь try catch, в котором ловить ВСЕ ошибки, то есть \Throwable и после этого скорее всего добавить throw с тем же исключением, поскольку вряд ли при ошибке БД имеет смысл продолжать работу скрипта. Но зависит от обстоятельств.

Если надо удалить файлы, то опять же, заключить в try catch загрузку файлов, то тут просто заключить в try catch, всё почистить и написать какое-нибудь сообщение пользователю.
Ответ написан
Vamp
@Vamp
Как правило, обычные ошибки не обрабатывают в таком обработчике, а конвертируют в ErrorException.

function error_handler(
    $error_code,
    $error_message,
    $error_file_name,
    $error_line
    // $error_context - не объявляйте этот аргумент. Он не существует.
  ){

    throw new ErrorException($error_message, 0, $error_code, $error_file_name, $error_line);

  }

  set_error_handler('error_handler', -1);

Ну а дальше ловите исключения как обычно.

// some code...

$host_db = '127.0.0.1';
$login_db = 'root';
$password_db = '';
$database_db = 'some_db';

$DB = new PDO('mysql:host=' . $host_db . ';dbname=' . $database_db, $login_db, $password_db);
$DB -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
    $DB -> beginTransaction();

    // some code...

    $DB -> commit();
} catch (\Throwable $e) {
    $DB->rollback();
}
// some code...
Ответ написан
@rPman
Если в скрипте произошла ошибка, то как мне откатить транзакцию
старайся чтобы все, что касается работы с каким то объектом, у которого состояние требует реакции (закрытие файла, транзакции бд и т.п.) то настоятельно рекомендуется описывать всю логику примерно на одном уровне/в одном месте

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

Язык программирования php рекомендует и предлагает для этого конструкцию try catch finaly, там где может произойти ошибка, в catch прописывай логику завершения именно данной секции (откатить транзакцию) и вызывай следующий throw по цепочке, в finaly же прописывай то что нужно исполнить в любом случае.

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

Войдите, чтобы написать ответ

Похожие вопросы