22

以下代码:

<?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

为什么会这样?

4

5 回答 5

29

A PDOStatement(您在 中$users)是一个前向光标。这意味着,一旦消耗(第一次foreach迭代),它就不会倒回到结果集的开头。

您可以在 之后关闭游标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它包装的对象的所有属性和方法。

于 2013-03-13T13:07:20.847 回答
18

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

PDOStatement 不是数组。使用foreachover 语句只是一种在内部使用熟悉的单向循环的语法糖。while如果您想多次循环数据,只需先将其选择为常规数组

$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/>";
}

也放弃那try..catch件事。不要使用它,而是 为 PHP 和 PDO设置正确的错误报告

于 2013-03-13T13:27:45.683 回答
10

这是因为您正在读取游标,而不是数组。这意味着您正在按顺序阅读结果,当您到达末尾时,您需要将光标重置到结果的开头以再次阅读它们。

如果您确实想多次读取结果,您可以使用fetchAll将结果读入一个真正的数组,然后它会按您的预期工作。

于 2013-03-13T13:05:07.907 回答
0
$users = $dbh->query($sql);
foreach ($users as $row) {
    print $row["name"] . "-" . $row["sex"] ."<br/>";
}
foreach ($users as $row) {
    print $row["name"] . "-" . $row["sex"] ."<br/>";
}

$users是一个PDOStatement可以迭代的对象。第一次迭代输出所有结果,第二次不做任何事情,因为您只能迭代结果一次。这是因为数据是从数据库中流式传输的,并且迭代结果foreach基本上是以下的简写:

while ($row = $users->fetch()) ...

完成该循环后,您需要在数据库端重置光标,然后才能再次循环它。

$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/>";
}

这里所有结果都由第一个循环输出。调用fetch将返回false,因为您已经用尽了结果集(见上文),因此您在尝试循环时遇到错误false

在最后一个示例中,您只是获取第一个结果行并对其进行循环。

于 2013-03-13T13:05:51.713 回答
-2
$row = $db->getAllRecords(DB_TBLPREFIX . '_payplans', '*', ' AND ppid = "' . $myid . '"');
foreach ($row as $value) {
    $bpprow = array_merge($bpprow, $value);
}

这是基于您可以全局使用此数据的 PHP 函数。

于 2022-02-15T08:55:53.850 回答