带有 foreach 和 fetch 的 PHP PDO

Posted

技术标签:

【中文标题】带有 foreach 和 fetch 的 PHP PDO【英文标题】:PHP PDO with foreach and fetch 【发布时间】:2013-03-01 10:13:49 【问题描述】:

以下代码:

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

再次执行相同的查询只是为了得到你已经得到的结果,正如接受的答案中所建议的那样,是一种疯狂。

foreach 语句只是常规单向 fetch() 循环的语法糖。如果要多次循环数据,请先将其选择为常规数组

$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 设置proper error reporting

【讨论】:

感谢您的提示,学习准备和执行是我的下一步。 @YourCommonSense 为什么你的答案中每个循环都有两个?我不是找错,只是学习…… 使用 pdo->query() 绝对不是使用库的错误方式。 exec() 和 query() 可以使用。唯一错误的用法是尝试通过该语句两次,他应该只有 fetchAll() 然后他可以通过数组迭代几次。如果您坚持使用 query() 是错误的,请给出适当的请说明原因。 我也不清楚使用query() 有什么问题,如mentioned in your tutorial。这个特定的实现有什么不理想的地方吗? @showdev 你是对的。我不记得这个答案的上下文,但肯定看起来很陌生,所以我编辑了它【参考方案2】:

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

你find the CachedPDOStatement class as a gist。缓存迭代器可能比将结果集存储到数组中更明智,因为它仍然提供它所包装的 PDOStatement 对象的所有属性和方法。

【讨论】:

谢谢,虽然看不清楚,但是你的例子对我以后肯定有用。 请查看另一个编辑,我有一个错字:在第一个 foreach 之后使用 $users-&gt;execute(); 将光标重置到结果集的开头。这很可能是您正在寻找的。缓存是一个更具体的解决方案,并不是真正必要的,你可以这样做$users-&gt;execute();。我添加它只是为了一般示例。 谢谢,第一个好像比较清楚,我去看看php手册中的execute函数。 是的,它更直接。方法在这里:php.net/manual/en/pdostatement.execute.php【参考方案3】:

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

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

【讨论】:

【参考方案4】:
$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 时会出错。

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

【讨论】:

以上是关于带有 foreach 和 fetch 的 PHP PDO的主要内容,如果未能解决你的问题,请参考以下文章

带有 PDO::FETCH_ASSOC 的 foreach 循环,提供的参数无效

PHP PDO fetch 和 foreach - 我没有得到第一列

使用 PHP 和 codeigniter 显示带有 foreach 函数的固定表

PHP:PDO fetch() 不显示结果

PHP中foreach函数用法?

在本地主机上运行的 Vue 应用程序中使用带有 php 文件的 JavaScript fetch() - 相对 URL 问题