PHP PDO 与 foreach 和 fetch

2022-08-30 18:54:26

下面的代码:

<?php
try {
    $dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
    echo "Connection is successful!<br/>";
    $sql = "SELECT * FROM users";
    $users = $dbh->query($sql);
    foreach ($users as $row) {
        print $row["name"] . "-" . $row["sex"] ."<br/>";
    }
    foreach ($users as $row) {
        print $row["name"] . "-" . $row["sex"] ."<br/>";
    }
    $dbh = null;
}
catch (PDOexception $e) {
    echo "Error is: " . $e-> etmessage();
}

输出:

Connection is successful!

person A-male
person B-female

运行“foreach”两次不是我的目的,我只是好奇为什么两个“foreach”语句只输出一次结果?

以下是类似的情况:

<?php
try {
    $dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
    echo "Connection is successful!<br/>";
    $sql = "SELECT * FROM users";
    $users = $dbh->query($sql);
    foreach ($users as $row) {
        print $row["name"] . "-" . $row["sex"] ."<br/>";
    }
    echo "<br/>";
    $result = $users->fetch(PDO::FETCH_ASSOC);
    foreach($result as $key => $value) {
        echo $key . "-" . $value . "<br/>";
    }
    $dbh = null;
}
catch (PDOexception $e) {
    echo "Error is: " . $e-> etmessage();
}

输出:

Connection is successful!

person A-male
person B-female

SCREAM: Error suppression ignored for
Warning: Invalid argument supplied for foreach()

但是当我从上面的代码中删除第一个“foreach”时,输出将变得正常:

<?php
try {
    $dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
    echo "Connection is successful!<br/>";
    $sql = "SELECT * FROM users";
    $users = $dbh->query($sql);

    echo "<br/>";
    $result = $users->fetch(PDO::FETCH_ASSOC);
    foreach($result as $key => $value) {
        echo $key . "-" . $value . "<br/>";
    }
    $dbh = null;
}
catch (PDOexception $e) {
    echo "Error is: " . $e-> etmessage();
}

输出:

Connection is successful!

user_id-0000000001
name-person A
sex-male

为什么会发生这种情况?


答案 1

A(您在 中具有)是正向游标。这意味着,一旦使用(第一次迭代),它就不会倒回到结果集的开头。PDOStatement$usersforeach

您可以在 之后关闭游标,然后再次执行该语句:foreach

$users       = $dbh->query($sql);
foreach ($users as $row) {
    print $row["name"] . " - " . $row["sex"] . "<br/>";
}

$users->execute();

foreach ($users as $row) {
    print $row["name"] . " - " . $row["sex"] . "<br/>";
}

或者,您可以使用使用全缓存量身定制的缓存进行缓存:CachingIterator

$users       = $dbh->query($sql);

$usersCached = new CachedPDOStatement($users);

foreach ($usersCached as $row) {
    print $row["name"] . " - " . $row["sex"] . "<br/>";
}
foreach ($usersCached as $row) {
    print $row["name"] . " - " . $row["sex"] . "<br/>";
}

您可以找到 CachedPDOStatement 类作为要点。缓存迭代器可能比将结果集存储到数组中更合理,因为它仍然提供它所包装的对象的所有属性和方法。PDOStatement


答案 2

再次执行相同的查询只是为了获得您已经拥有的结果,正如接受的答案中所建议的那样,这是一种疯狂。添加一些额外的代码来执行如此简单的任务也是没有意义的。我不知道为什么人们会设计出如此复杂和低效的方法,使这种原始的、最基本的行动复杂化。

PDOStatement 不是一个数组。在语句上使用只是一种语法糖,它在内部使用熟悉的单向循环。如果要多次循环访问数据,只需先将其作为常规数组选择foreachwhile

$sql = "SELECT * FROM users";
$stm = $dbh->query($sql);
// here you go:
$users = $stm->fetchAll();

然后根据需要多次使用此数组:

foreach ($users as $row) {
    print $row["name"] . "-" . $row["sex"] ."<br/>";
}
echo "<br/>";
foreach ($users as $row) {
    print $row["name"] . "-" . $row["sex"] ."<br/>";
}

也戒掉那个东西。不要使用它,但要为 PHP 和 PDO 设置正确的错误报告try..catch


推荐