Какой код лучше использовать, чтобы отлавливать ошибки MySQL?

Подскажите, пожалуйста, какой код лучше использовать, чтобы отлавливать ошибки MySQL?

Такой:

mysqli_query($link, $query) or die(mysqli_error() .$query);


Или вот такой:

mysqli_query($link, $query) or trigger_error(mysqli_error() .$query);


И почему один лучше другого?
  • Вопрос задан
  • 4985 просмотров
Решения вопроса 1
FanatPHP
@FanatPHP
Чебуратор тега РНР
Если выбирать из этих двух, то второй, разумеется. Он на порядок лучше первого:
- в отличие от первого, он будет выдавать ошибки туда же, куда и весь остальной РНР. На машине разработчика это может быть экран, на боевом сайте - лог. Первый плюёт ошибки в браузер ВСЕГДА, чего на боевом сайте не должно быть никогда
- в отличие от первого, он сообщит номер строки и имя файла, где произошла ошибка, что является критически важным для того самого отлова ошибки. Рекомендую попробовать поискать ошибочный запрос в коде на пару тысяч строк по сообщению от первого варианта. Подробнее про то, как правильно обрабатывать ошибки, можно почитать здесь: Обработка ошибок, часть 1

Примечание: на самом деле ни тот, ни другой коды работать не будут, поскольку mysqli_error() тоже требует $link в обязательном порядке.

Дальше уже идут более продвинутые варианты.
Для начала, mysqli умеет кидать исключения из коробки:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

и после этого любая ошибка mysqli будет порождать исключение.
Но у этого подхода есть два минуса:
1. Такой вариант может понадобиться только в случае, если обращения к mysqli_query разбросаны по всему коду, чего делать нельзя ни в коем случае.
2. В брошенном исключении будет отсутствовать сам запрос, который может быть очень полезен при отладке.

Поэтому идеальным вариантом будет такой:
Во-первых, все обращения к mysqli API в обязательном порядке надо завернуть в какую-либо библиотеку, которая возьмёт на себя выполнение всей грязной и повторяющейся работы. Пример такой библиотеки - SafeMysql
Во-вторых, в этой библиотеке оформить код обращения к mysqli_query такм образом:
$res = $link->query($query);
if (!$res) throw new Exception($link->error() ." [$query]");

В результате мы получим идеальную обработку ошибок:
- этот код уже из коробки будет так же следовать настройкам РНР, и не будет выдавать ошибки на экран на боевом сервере, но при этом программист всегда будет о ней проинформирован.
- этот код будет выдавать трассировку вызовов - бесценную информацию, без которой найти место, где произошла ошибка, будет очень сложно.
- брошенное исключение можно будет поймать в хендлере или блоке try..catch (однако если нет опыта работы с этими двумя вещами, то на первое время лучше оставить исключение как есть. В обработке ошибок есть много нюансов, неизвестных среднему кодеру, и поэтому лучше оставить эту задачу для РНР).
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
Ни один из двух. Во первых: научитесь работать с тем, что вам мускул возвращает (false => нашёл ошибку -> бросил исключение). Забудьте про конструкцию: or die/or exception, etc... Это не только извращение над самим собой, но и другими программистами, которые будут читать код после вас.
Использование trigger_error без callback (set_exception_handler) тоже не желательно.
Ответ написан
Комментировать
svd71
@svd71
это зависит, какую цельвы ставите. Die() останавливает выполение всех скриптов в запросе с выводом сообщения. trigger_error переводит ошибку на какую либо обработку (напрмер на запись в лог-файл или отправку сообщения администратору).

Но оба варианта полохи, если не пользоваться PDO.
Ответ написан
Комментировать
Лучше записывать ошибки в лог-файл. На рабочей версии ошибок не должно быть вовсе, т.е. не должно быть лог-файла. Появился лог-файл - значит дело плохо.
//---------------- Процедура подключения к базе данных -----------------------//
function dbconnect() {
   // Используем статическую переменную для сохранения значений внутри функции
	static $database;
	if (!isset($database)) {
		// Соединение по IP самое быстрое
		// Сразу задаём кодировку соединения
		$database = new PDO('mysql:host=127.0.0.1;dbname=robotbattle', "marvin", "god", array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''));
		// Устанавливаем уровень показа ошибок базы
		$database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	}
	return $database;
}
//----------------------------------------------------------------------------//

//--------------------- Функция выполнения запросов --------------------------//
function sql_query($query) {
	global $errors;
	
	try { 
      $return = dbconnect()->query($query);
   } 
   catch (PDOException $e) { 
      $error = $e->getMessage();
  		writelog('sql_error', date("y.m.d H:m:s")."\t".$error);
		$errors .= $error;
		return false;
   }

	return $return;
}
//----------------------------------------------------------------------------//

//------------------------ Процедура записи в лог фаил -----------------------//
function writelog($typelog, $log_text) {
	file_put_contents('logs/'.$typelog.'.txt', "$log_text\r\n", FILE_APPEND | LOCK_EX);
}
//----------------------------------------------------------------------------//
Ответ написан
Ваш ответ на вопрос

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

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