Какой код лучше использовать, чтобы отлавливать ошибки MySQL?
Если выбирать из этих двух, то второй, разумеется. Он на порядок лучше первого:
- в отличие от первого, он будет выдавать ошибки туда же, куда и весь остальной РНР. На машине разработчика это может быть экран, на боевом сайте - лог. Первый плюёт ошибки в браузер ВСЕГДА, чего на боевом сайте не должно быть никогда
- в отличие от первого, он сообщит номер строки и имя файла, где произошла ошибка, что является критически важным для того самого отлова ошибки. Рекомендую попробовать поискать ошибочный запрос в коде на пару тысяч строк по сообщению от первого варианта. Подробнее про то, как правильно обрабатывать ошибки, можно почитать здесь: Обработка ошибок, часть 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 (однако если нет опыта работы с этими двумя вещами, то на первое время лучше оставить исключение как есть. В обработке ошибок есть много нюансов, неизвестных среднему кодеру, и поэтому лучше оставить эту задачу для РНР).
Лучше записывать ошибки в лог-файл. На рабочей версии ошибок не должно быть вовсе, т.е. не должно быть лог-файла. Появился лог-файл - значит дело плохо.//---------------- Процедура подключения к базе данных -----------------------//
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);
}
//----------------------------------------------------------------------------//