模拟PDO获取失败情况

时间:2017-09-21 11:50:20

标签: php mysql pdo exception-handling fetch

符合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

3 个答案:

答案 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将返回一个空数组。
  • PDOStatement::fetch官方页面上未记录PDO::FETCH_KEY_PAIR常量。

P.S:

我要感谢所有试图帮助我找到问题答案的用户。你有我的谢意!

用于测试的代码:

<?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有类似的问题。

以上将返回;

    查询失败时
  • false
  • 如果没有找到行,则获取一个空数组
  • 找到的适当结果集
  • 如果找不到fetchColumn,则
  • null
  • 如果找到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

你可以采取更多措施来改善上述目标,但希望你能得到这个想法。

相关问题