符合php文档,PDO方法fetch()在失败时找不到记录 AND 时返回值FALSE
(例如,当数据库出现问题时)访问)。
我们假设,我将PHP错误报告系统设置为在失败时抛出异常:
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
我需要一个案例,fetch()
方法会引发异常。为什么?因为我想检查一下,要100%确定fetch()
在失败时抛出异常,并且在失败时不会返回FALSE
。
如果是这种情况,那么我确实会考虑FALSE
返回的fetch()
,因为没有在db表中找到任何记录。
所以,我的问题是:您是否知道如何模拟fetch()
方法的失败情况?
谢谢。
P.S。:我的问题的答案将帮助我找到另一个问题的答案:PHP PDO fetch returns FALSE when no records found AND on failure
修改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();
}
我使用了以下create table语法:
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
答案 0 :(得分:3)
最后,我发现了一个允许我测试的案例,如果PDOStatement::fetch
确实会在失败时抛出异常。
文章Taking advantage of PDO’s fetch modes介绍了这种情况。它基于使用PDOStatement::fetchAll
并将PDO::FETCH_KEY_PAIR
常量作为参数传递。
所以,我自己做了一个测试。但我使用了PDOStatement::fetch
方法。根据定义,PDO::FETCH_KEY_PAIR
常量要求数据源表仅包含两列。在我的测试中,我定义了三个表列。 PDOStatement::fetch
已经认识到这种情况是失败的并且抛出了异常:
SQLSTATE [HY000]:常规错误:PDO :: FETCH_KEY_PAIR获取模式 要求结果集包含extactly 2列。
PDOStatement::fetch
会返回FALSE
。 PDOStatement::fetch
抛出 - 确实 - 在发生故障时例外。 PDOStatement::fetchAll
将返回一个空数组。PDO::FETCH_KEY_PAIR
常量。我要感谢所有试图帮助我找到问题答案的用户。你有我的谢意!
<?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
答案 1 :(得分:0)
如果出现错误,使用PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
fetch将始终抛出异常。你可以处理catch块中的那些,它返回的并不重要。因此,如果您没有捕获异常并且它返回false,则可以安全地假设它是由于空集。这是处理PDO错误的一种非常有效的方法。要回答您的问题,有很多方法可以模拟错误。最基本的是不正确的查询语法。您还可以尝试绑定不存在的参数,绑定错误数量的参数等。使用此方案的时间越长,您将看到的错误/异常类型越多。它非常有效,因为每个错误都包含一条详细的消息来帮助您调试它。
答案 2 :(得分:-1)
除非你需要PDOStatement作为循环,否则你可以在方法/函数中使用fetchAll来获得你想要的结果。只需执行fetchAll而不是fetch,检查false,并根据需要返回。在这种情况下,您的查询应该确保只返回1行。
像这样;
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有类似的问题。
以上将返回;
扫描您的代码示例,您可以这样实现;
$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
你可以采取更多措施来改善上述目标,但希望你能得到这个想法。