Intereting Posts
Нужна помощь в PHP-петле Как удалить пустые теги абзаца из строки? Как оптимизировать запрос mysql, получая категории и подкатегории WordPress: загрузить полноразмерное изображение в миниатюре Форма обратной связи PHP и HTML Получение ответа HTML вместо JSON в android Какая польза от использования filter_has_var () над isset () Ошибка SOAP PHP. Не удалось найти <определения> Хранение содержимого массива PHP в базе данных MySQL Экспорт данных таблицы в файл csv с помощью mysqldump Когда я убираю все входные данные, иногда он оставляет в строке строчки (\) и вставляет их в базу данных. Почему это происходит и как я могу это решить? Silex SwiftMailer не выполняет подключение SMTP после выполнения Использование терминала, как мне заставить OS X использовать версию MAMPs PHP Как узнать исполняемый исполняемый файл PHP? Отключить маршрутизацию Laravel для определенной папки / маршрута

Имитировать ситуацию с отказом PDO

В соответствии с php-документами метод PDO fetch () возвращает значение FALSE как при отсутствии записей, так и при сбое (например, когда что-то пойдет не так в отношении доступа к базе данных).

Предположим, я установил систему отчетов об ошибках PHP для исключения исключений при сбое:

 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION 

Мне нужен случай, ситуация, в которой метод fetch() генерирует исключение. Зачем? Поскольку я хочу проверить, чтобы быть уверенным на 100%, что fetch() выдает исключение при ошибке и не просто возвращает FALSE при ошибке.

Если бы это было так, то я бы действительно рассмотрел FALSE возвращенный fetch() за того, что не нашел записей в таблице db.

Итак, мой вопрос будет: знаете ли вы способ моделирования ситуации сбоя для метода fetch() ?

Спасибо.

PS : Ответ на мой вопрос поможет мне найти ответ на мой другой вопрос: PHP PDO fetch возвращает FALSE, когда нет записей и ошибок


Изменить 1:

Я также подготовил пример, чтобы показать, как я обрабатываю исключения. Речь идет о простом sql-запросе, который выводит пользователя из таблицы users :

 <?php // Activate error reporting. error_reporting(E_ALL); ini_set('display_errors', 1); try { // Create a PDO instance as db connection to a MySQL db. $connection = new PDO( 'mysql:host=localhost;port=3306;dbname=mydb;charset=utf8' , 'myuser' , 'mypass' , array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => FALSE, PDO::ATTR_PERSISTENT => TRUE ) ); // Define the sql statement. $sql = 'SELECT * FROM users WHERE name = :name'; /* * Prepare and validate the sql statement. * * -------------------------------------------------------------------------------- * If the database server cannot successfully prepare the statement, PDO::prepare() * returns FALSE or emits PDOException (depending on error handling settings). * -------------------------------------------------------------------------------- */ $statement = $connection->prepare($sql); if (!$statement) { throw new UnexpectedValueException('The sql statement could not be prepared!'); } // Bind the input parameter to the prepared statement. $bound = $statement->bindValue(':name', 'Sarah', PDO::PARAM_STR); // Validate the binding of the input parameter. if (!$bound) { throw new UnexpectedValueException('An input parameter can not be bound!'); } /* * Execute the prepared statement. * * ------------------------------------------------------------------ * PDOStatement::execute returns TRUE on success or FALSE on failure. * ------------------------------------------------------------------ */ $executed = $statement->execute(); if (!$executed) { throw new UnexpectedValueException('The prepared statement can not be executed!'); } /* * Fetch and validate the result set. * * ========================================================= * Note: * ========================================================= * PDOStatement::fetch returns FALSE not only on failure, * but ALSO when no record is found! * * Instead, PDOStatement::fetchAll returns FALSE on failure, * but an empty array if no record is found. This is the * natural, desired behaviour. * ========================================================= */ $resultset = $statement->fetch(PDO::FETCH_ASSOC); if ($resultset === FALSE) { throw new UnexpectedValueException('Fetching data failed!'); } // Display the result set. var_dump($resultset); echo '<pre>' . print_r($resultset, TRUE) . '</pre>'; // Close connection. $connection = NULL; } catch (PDOException $exc) { echo '<pre>' . print_r($exc, TRUE) . '</pre>'; exit(); } catch (Exception $exc) { echo '<pre>' . print_r($exc, TRUE) . '</pre>'; exit(); } - <?php // Activate error reporting. error_reporting(E_ALL); ini_set('display_errors', 1); try { // Create a PDO instance as db connection to a MySQL db. $connection = new PDO( 'mysql:host=localhost;port=3306;dbname=mydb;charset=utf8' , 'myuser' , 'mypass' , array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => FALSE, PDO::ATTR_PERSISTENT => TRUE ) ); // Define the sql statement. $sql = 'SELECT * FROM users WHERE name = :name'; /* * Prepare and validate the sql statement. * * -------------------------------------------------------------------------------- * If the database server cannot successfully prepare the statement, PDO::prepare() * returns FALSE or emits PDOException (depending on error handling settings). * -------------------------------------------------------------------------------- */ $statement = $connection->prepare($sql); if (!$statement) { throw new UnexpectedValueException('The sql statement could not be prepared!'); } // Bind the input parameter to the prepared statement. $bound = $statement->bindValue(':name', 'Sarah', PDO::PARAM_STR); // Validate the binding of the input parameter. if (!$bound) { throw new UnexpectedValueException('An input parameter can not be bound!'); } /* * Execute the prepared statement. * * ------------------------------------------------------------------ * PDOStatement::execute returns TRUE on success or FALSE on failure. * ------------------------------------------------------------------ */ $executed = $statement->execute(); if (!$executed) { throw new UnexpectedValueException('The prepared statement can not be executed!'); } /* * Fetch and validate the result set. * * ========================================================= * Note: * ========================================================= * PDOStatement::fetch returns FALSE not only on failure, * but ALSO when no record is found! * * Instead, PDOStatement::fetchAll returns FALSE on failure, * but an empty array if no record is found. This is the * natural, desired behaviour. * ========================================================= */ $resultset = $statement->fetch(PDO::FETCH_ASSOC); if ($resultset === FALSE) { throw new UnexpectedValueException('Fetching data failed!'); } // Display the result set. var_dump($resultset); echo '<pre>' . print_r($resultset, TRUE) . '</pre>'; // Close connection. $connection = NULL; } catch (PDOException $exc) { echo '<pre>' . print_r($exc, TRUE) . '</pre>'; exit(); } catch (Exception $exc) { echo '<pre>' . print_r($exc, TRUE) . '</pre>'; exit(); } 

Я использовал следующий синтаксис таблицы создания:

 DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=124 DEFAULT CHARSET=utf8; 

и следующие значения таблицы:

 INSERT INTO `users` (`id`, `name`) VALUES (1,'Sarah'), (2,'John'); 

Итак, таблица выглядит так:

 id name -------- 1 Sarah 2 John 

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

Кредиты:

В статье Воспользовавшись режимами выборки PDO, возникает такая ситуация. Он основан на использовании PDOStatement::fetchAll с константой PDO::FETCH_KEY_PAIR переданной как аргумент.

Контрольная работа:

Итак, я сам проверил тест. Но вместо этого я использовал метод PDOStatement::fetch . Для определения константа PDO::FETCH_KEY_PAIR требует, чтобы таблица источника данных содержала только два столбца. В моем тесте я определил три столбца таблицы. PDOStatement::fetch признал эту ситуацию неудачей и PDOStatement::fetch исключение:

SQLSTATE [HY000]: общая ошибка: режим выборки PDO :: FETCH_KEY_PAIR требует, чтобы результирующий набор содержал не более 2 столбцов.

Вывод:

  • PDOStatement::fetch возвращает FALSE , если записи не найдены.
  • PDOStatement::fetch throws – действительно – исключение в случае сбоя.

Заметки:

  • Вместо этого PDOStatement::fetchAll возвращает пустой массив, если записи не найдены.
  • Константа PDO::FETCH_KEY_PAIR не зарегистрирована на официальной странице PDOStatement :: fetch .

PS:

Я хочу поблагодарить всех пользователей, которые пытались помочь мне найти ответ на мой вопрос. У вас есть моя оценка!


Код, используемый для тестирования:

 <?php // Activate error reporting. error_reporting(E_ALL); ini_set('display_errors', 1); try { // Create a PDO instance as db connection to a MySQL db. $connection = new PDO( 'mysql:host=localhost;port=3306;dbname=tests;charset=utf8' , 'root' , 'root' , array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => FALSE, PDO::ATTR_PERSISTENT => TRUE ) ); // Define the sql statement. $sql = 'SELECT * FROM users WHERE name = :name'; /* * Prepare the sql statement. * * -------------------------------------------------------------------------------- * If the database server cannot successfully prepare the statement, PDO::prepare() * returns FALSE or emits PDOException (depending on error handling settings). * -------------------------------------------------------------------------------- */ $statement = $connection->prepare($sql); // Validate the preparation of the sql statement. if (!$statement) { throw new UnexpectedValueException('The sql statement could not be prepared!'); } // Bind the input parameter to the prepared statement. $bound = $statement->bindValue(':name', 'Sarah', PDO::PARAM_STR); // Validate the binding of the input parameter. if (!$bound) { throw new UnexpectedValueException('An input parameter can not be bound!'); } /* * Execute the prepared statement. * * ------------------------------------------------------------------ * PDOStatement::execute returns TRUE on success or FALSE on failure. * ------------------------------------------------------------------ */ $executed = $statement->execute(); // Validate the execution of the prepared statement. if (!$executed) { throw new UnexpectedValueException('The prepared statement can not be executed!'); } // Fetch the result set. $resultset = $statement->fetch(PDO::FETCH_KEY_PAIR); // If no records found, define the result set as an empty array. if ($resultset === FALSE) { $resultset = []; } // Display the result set. var_dump($resultset); // Close connection. $connection = NULL; } catch (PDOException $exc) { echo '<pre>' . print_r($exc->getMessage(), TRUE) . '</pre>'; exit(); } catch (Exception $exc) { echo '<pre>' . print_r($exc->getMessage(), TRUE) . '</pre>'; exit(); } 

Создать синтаксис таблицы:

 DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) DEFAULT NULL, `phone` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; 

Вставить синтаксис значений:

 INSERT INTO `users` (`id`, `name`, `phone`) VALUES (1,'Sarah','12345'), (2,'John','67890'); 

Значения таблиц:

 id name phone ----------------- 1 Sarah 12345 2 John 67890 

С PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION выборка всегда будет генерировать исключение, если есть ошибка. Вы можете обращаться с теми, кто находится в вашем блоке catch, и не имеет значения, что он вернул. Поэтому, если вы не заметили исключение и вернули false, вы можете с уверенностью предположить, что это было из-за пустого набора. Это очень эффективный способ обработки ошибок PDO. Чтобы ответить на ваш вопрос, существует множество способов моделирования ошибки. Самый простой – это неправильный синтаксис запроса. Вы также можете попытаться связать параметр, которого нет, связать неправильное количество параметров и т. Д. Чем дольше вы используете эту схему, тем больше типов ошибок / исключений вы увидите. Это очень эффективно, поскольку каждая ошибка содержит подробное сообщение, которое поможет вам отладить его.

Если вам не нужен PDOStatement для цикла, вы можете использовать fetchAll в методе / функции, чтобы получить результат, который вы ищете. Просто сделайте fetchAll вместо выборки, проверьте значение false и при необходимости верните. В этом случае ваш запрос должен убедиться, что возвращается только одна строка.

Что-то вроде этого;

 function fetch(\PDOStatement $pdo_stmt) { // use fetchAll as an empty result set is returned by PDO as false using fetch() $result = $pdo_stmt->fetchAll(\PDO::FETCH_ASSOC); if ($result !== false) { return !empty($result) ? $result[0] : []; } return false; } function fetchColumn(\PDOStatement $pdo_stmt) { // this will return false if no rows or not found... $result = $pdo_stmt->fetchColumn(); if (empty($pdo_stmt->errorInfo())) { return $result !== false ? $result : null; } return false; } 

Обратите внимание, что fetchColumn имеет аналогичную проблему.

Вышеизложенное вернется;

  • false при ошибке запроса
  • пустой массив для извлечения, если строки не найдены
  • соответствующий набор результатов для извлечения, если найден
  • null для fetchColumn, если не найден
  • значение столбца для fetchColumn, если найдено

Сканируя образец кода, вы можете реализовать его так;

 $sql = 'SELECT * FROM users WHERE name = :name'; $stmt = $connection->prepare($sql); $stmt->bindValue(':name', 'Sarah'); $executed = $stmt->execute(); if (!$executed) { throw new UnexpectedValueException('The prepared statement can not be executed!'); } $result_set = fetch($stmt); if ($result_set === false) { throw new UnexpectedValueException('Fetching data failed!'); } // handle result set 

Вы можете сделать больше, чтобы улучшить выше, но, надеюсь, вы получите эту идею.