简体   繁体   English

PHP PDO foreach 和 fetch

[英]PHP PDO with foreach and fetch

The following code:以下代码:

<?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();
}

Output: Output:

Connection is successful!

person A-male
person B-female

Running "foreach" twice is not my purpose, I'm just curious why TWO "foreach" statements only output the result once?运行“foreach”两次不是我的目的,我只是好奇为什么两个“foreach”语句只有一次 output 结果?

Following is the similar case:以下是类似案例:

<?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();
}

Output: Output:

Connection is successful!

person A-male
person B-female

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

But when I delete the first "foreach" from the above codes, the output will become normal:但是当我从上面的代码中删除第一个“foreach”时,output 将变得正常:

<?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();
}

Output: Output:

Connection is successful!

user_id-0000000001
name-person A
sex-male

Why does this happen?为什么会这样?

A PDOStatement (which you have in $users ) is a forward-cursor. PDOStatement (您在$users )是一个前向光标。 That means, once consumed (the first foreach iteration), it won't rewind to the beginning of the resultset.这意味着,一旦使用(第一次foreach迭代),它就不会倒回到结果集的开头。

You can close the cursor after the foreach and execute the statement again:您可以在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/>";
}

Or you could cache using tailored CachingIterator with a 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/>";
}

You find the CachedPDOStatement class as a gist .发现CachedPDOStatement类是一个要点 The caching iterator is probably more sane than storing the result set into an array because it still offers all properties and methods of the PDOStatement object it has wrapped.缓存迭代器可能比将结果集存储到数组中更合理,因为它仍然提供它所包装的PDOStatement对象的所有属性和方法。

foreach over a statement is just a syntax sugar for the regular one-way fetch() loop.语句上的 foreach 只是常规单向 fetch() 循环的语法糖。 If you want to loop over your data more than once, select it as a regular array first如果要多次循环数据,请先将其选择为常规数组

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

Also quit that try..catch thing.也退出那个try..catch东西。 Don't use it, but set the proper error reporting for PHP and PDO不要使用它,而是为 PHP 和 PDO 设置正确的错误报告

This is because you are reading a cursor, not an array.这是因为您正在读取游标,而不是数组。 This means that you are reading sequentially through the results and when you get to the end you would need to reset the cursor to the beginning of the results to read them again.这意味着您正在按顺序阅读结果,当您读到最后时,您需要将光标重置到结果的开头才能再次阅读它们。

If you did want to read over the results multiple times, you could use fetchAll to read the results into a true array and then it would work as you are expecting.如果您确实想多次读取结果,您可以使用fetchAll将结果读入一个真正的数组,然后它会按您的预期工作。

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

Here $users is a PDOStatement object over which you can iterate.这里$users是一个PDOStatement对象,您可以对其进行迭代。 The first iteration outputs all results, the second does nothing since you can only iterate over the result once.第一次迭代输出所有结果,第二次不执行任何操作,因为您只能迭代一次结果。 That's because the data is being streamed from the database and iterating over the result with foreach is essentially shorthand for:那是因为数据是从数据库流式传输的,并且使用foreach迭代结果本质上是以下内容的简写:

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

Once you've completed that loop, you need to reset the cursor on the database side before you can loop over it again.完成该循环后,您需要在数据库端重置游标,然后才能再次循环它。

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

Here all results are being output by the first loop.这里所有结果都由第一个循环输出。 The call to fetch will return false , since you have already exhausted the result set (see above), so you get an error trying to loop over false .fetch的调用将返回false ,因为您已经用尽了结果集(见上文),因此您在尝试遍历false会遇到错误。

In the last example you are simply fetching the first result row and are looping over it.在最后一个示例中,您只是获取第一个结果行并对其进行循环。

$row = $db->getAllRecords(DB_TBLPREFIX . '_payplans', '*', ' AND ppid = "' . $myid . '"');
foreach ($row as $value) {
    $bpprow = array_merge($bpprow, $value);
}

This is based on PHP functions where you can globally use this data.这基于 PHP 函数,您可以在其中全局使用此数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM