PHP try/catch и фатальная ошибка
Я использую следующий скрипт для использования базы данных с помощью PHP:
try{
$db = new PDO('mysql:host='.$host.';port='.$port.';dbname='.$db, $user, $pass, $options);
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Теперь я хочу использовать этот дескриптор базы данных для выполнения запроса с помощью этого кода:
try{
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Вот проблема:
- Когда соединение с БД в порядке, все работает,
- Когда соединение терпит неудачу, но я не использую БД, у меня есть массив
$GLOBALS['errors'][]
и скрипт все еще работает после этого, - Когда соединение с БД завершилось неудачно, я получаю следующую фатальную ошибку:
Примечание. Неопределенная переменная: db в C:\xampp\htdocs [...]\test.php в строке 32
Неустранимая ошибка: вызовите функцию-член prepare() для не-объекта в C:\xampp\htdocs [...]\test.php в строке 32
Примечание. Строка 32 - это команда $query = $db->prepare(...)
.
То есть, сценарий падает, а try/catch кажется бесполезным. Вы знаете, почему эта вторая попытка/уловка не работает и как ее решить?
Спасибо за помощь!
EDIT: Есть действительно хорошие ответы. Я подтвердил то, что не совсем то, что я хотел сделать, но это, вероятно, лучший подход.
Ответы
Ответ 1
try
/catch
блоки работают только для сброшенных исключений (throw Exception
или подкласс Exception
). Вы не можете поймать фатальные ошибки, используя try
/catch
.
Если ваше соединение с БД не может быть установлено, я считаю его фатальным, так как вам, вероятно, нужна ваша БД, чтобы сделать что-либо значимое на странице.
PDO
выдает исключение, если соединение не может быть установлено. Ваша конкретная проблема заключается в том, что $db
не определяется при попытке вызвать метод с ним, чтобы вы получили нулевой указатель (сорт), который является фатальным. Вместо того, чтобы перепрыгивать, if ($db == null)
обручи, как предлагают другие, вы должны просто исправить свой код, чтобы убедиться, что $db
либо всегда определяется, когда вам это нужно, либо имеет менее хрупкий способ убедиться, что соединение с БД доступен в коде, который его использует.
Если вы действительно хотите "уловить" фатальные ошибки, используйте set_error_handler
, но это все еще останавливает выполнение сценария при фатальных ошибках.
Ответ 2
В PHP7, теперь мы можем использовать try catch fatal error с простой работой
try {
do some thing evil
} catch (Error $e) {
echo 'Now you can catch me!';
}
Но, как правило, мы должны избегать использования catch Error, потому что она подразумевает пропуск кода, который принадлежит программисту :-)
Ответ 3
Если соединение с базой данных завершается неудачно, $db
с первой try.. catch
блокирует try.. catch
. Вот почему позже вы не можете использовать член не-объекта, в вашем случае $db->prepare(...)
. Перед использованием этого добавить
if ($db) {
// other try catch statement
}
Это гарантирует, что у вас есть экземпляр db для работы с ним.
Ответ 4
Почему вы используете try... catch
заявления для объявления этого. Замените это:
try{
$db = new PDO('mysql:host='.$host.';port='.$port.';dbname='.$db, $user, $pass, $options);
}
С:
$db = new PDO('mysql:host='.$host.';port='.$port.';dbname='.$db, $user, $pass, $options) or die("Cannot Create PDO!");
Или на вашем пути:
$db = new PDO('mysql:host='.$host.';port='.$port.';dbname='.$db, $user, $pass, $options) or ($GLOBALS['errors'][] = "Cannot Create PDO!");
Ответ 5
Попробуйте добавить следующую инструкцию if:
if ($db) {
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(....);
}
else die('Connection lost');
Ответ 6
try{
if(!is_null($db))
{
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Ответ 7
Я не буду сообщать, что уже было написано о тестировании, если $db
пуст. Просто добавьте, что "чистым" решением является искусственное создание исключения, если соединение с базой данных не удалось:
if ($db == NULL) throw new Exception('Connection failed.');
Вставьте предыдущую строку в try - catch
следующим образом:
try{
// This line create an exception if $db is empty
if ($db == NULL) throw new Exception('Connection failed.');
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Надеюсь, это поможет другим!