php - fatal - throw pdoexception
Simular una situación de falla de captación de PDO (3)
Con PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
fetch arrojará siempre una excepción si hay un error. Puedes manejarlos en tu bloque catch y no importa lo que devuelva. Por lo tanto, si no captó una excepción y devolvió el valor falso, puede asumir con seguridad que se debió a un conjunto vacío. Esta es una forma muy efectiva de manejar errores de PDO. Para responder a su pregunta, hay muchas maneras de simular un error. El más básico es la sintaxis de consulta incorrecta. También puede intentar vincular un parámetro que no está allí, enlazar el número incorrecto de parámetros, etc. Cuanto más tiempo utilice este esquema, más tipos de errores / excepciones verá. Es muy efectivo ya que cada error incluye un mensaje detallado para ayudarlo a depurarlo.
Conforme a los documentos php, el método PDO fetch () devuelve el valor FALSE
cuando no se encuentran registros AND en caso de error (por ejemplo, cuando algo va mal con respecto al acceso a la base de datos).
Supongamos que configuré el sistema de informe de errores de PHP para lanzar excepciones en caso de error:
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
Necesito un caso, una situación en la que el método fetch()
lanzará una excepción. ¿Por qué? Como quiero comprobar, estoy 100% seguro de que fetch()
arroja una excepción en caso de error y no solo devuelve FALSE
en caso de error.
Si ese fuera el caso, de hecho consideraría el FALSE
devuelto por fetch()
como resultado de no encontrar ningún registro en la tabla db.
Entonces, mi pregunta sería: ¿Conoces una manera de simular una situación de falla para el método fetch()
?
Gracias.
PD : La respuesta a mi pregunta me ayudará a encontrar la respuesta para mi otra pregunta: la obtención de PDO PHP devuelve FALSE cuando no se encontraron registros AND en caso de error
Editar 1:
También preparé un ejemplo para mostrar cómo manejo las excepciones. Se trata de una simple consulta SQL, que busca un usuario de una tabla de 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();
}
Utilicé la siguiente sintaxis de tabla de creación:
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;
y los siguientes valores de tabla:
INSERT INTO `users` (`id`, `name`)
VALUES
(1,''Sarah''),
(2,''John'');
Entonces, la tabla se ve así:
id name
--------
1 Sarah
2 John
A menos que necesite el PDOStatement para un bucle, puede usar fetchAll en un método / función para obtener el resultado que está buscando. Solo haga un fetchTodos en lugar de una búsqueda, verifique si es falso y devuelva según sea necesario. En este caso, su consulta debería asegurarse de que solo se devuelva 1 fila.
Algo como esto;
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;
}
Tenga en cuenta que fetchColumn tiene un problema similar.
Lo anterior regresará;
- falso en la falla de consulta
- una matriz vacía para recuperar si no se encontraron filas
- conjunto de resultados apropiado para buscar si se encuentra
- null para fetchColumn si no se encuentra
- valor de columna para fetchColumn si se encuentra
Al escanear su muestra de código, puede implementarlo de esa manera;
$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
Hay más que puedes hacer para mejorar lo anterior, pero ojalá entiendas la idea.
Finalmente, encontré un caso, que me permitió probar, si PDOStatement::fetch
lanzara una excepción en caso de falla.
Créditos:
El artículo Aprovechando los modos de búsqueda de PDO presenta tal situación. Se basa en el uso de PDOStatement::fetchAll
con la constante PDO::FETCH_KEY_PAIR
pasada como argumento.
Prueba:
Entonces, realicé una prueba yo mismo. Pero usé el método PDOStatement::fetch
lugar. Por definición, la constante PDO::FETCH_KEY_PAIR
requiere que la tabla fuente de datos contenga solo dos columnas. En mi prueba, definí tres columnas de tabla. PDOStatement::fetch
ha reconocido esta situación como un error y ha lanzado una excepción:
SQLSTATE [HY000]: error general: el modo de recuperación PDO :: FETCH_KEY_PAIR requiere que el conjunto de resultados contenga 2 columnas extactly.
Conclusión:
-
PDOStatement::fetch
devuelveFALSE
, si no se encuentran registros. -
PDOStatement::fetch
throws - de hecho - una excepción en caso de error.
Notas:
- En cambio,
PDOStatement::fetchAll
devuelve una matriz vacía, si no se encuentran registros. - La constante
PDO::FETCH_KEY_PAIR
no está documentada en la página oficial PDOStatement :: fetch .
PD:
Quiero agradecer a todos los usuarios que trataron de ayudarme a encontrar la respuesta a mi pregunta. ¡Tienes mi agradecimiento!
El código usado para probar:
<?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();
}
Crear sintaxis de tabla:
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;
Insertar sintaxis de valores:
INSERT INTO `users` (`id`, `name`, `phone`)
VALUES
(1,''Sarah'',''12345''),
(2,''John'',''67890'');
Valores de tabla:
id name phone
-----------------
1 Sarah 12345
2 John 67890