带有foreach和fetch的PHP PDO

时间:2013-03-13 12:55:41

标签: php mysql pdo foreach fetch

以下代码:

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

任何人都知道为什么会这样?我只是一个PHP初学者,谢谢你的帮助!

4 个答案:

答案 0 :(得分:20)

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

或者您可以使用带有fullcache的定制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对象的所有属性和方法。

答案 1 :(得分:11)

foreach over a statement只是常规单向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设置正确的错误报告

答案 2 :(得分:8)

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

如果您确实希望多次读取结果,可以使用fetchAll(http://www.php.net/manual/en/pdostatement.fetchall.php)将结果读入真实数组,然后按预期工作。

答案 3 :(得分: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时出错。

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