【问题标题】:Use PDO statement multiple times when using multiple foreach loops使用多个 foreach 循环时多次使用 PDO 语句
【发布时间】:2016-07-25 12:21:49
【问题描述】:

我有以下代码:

if(!empty($postCountryAdd)) {
$sqlQueryLocalityAdd = $dbh->prepare("SELECT DISTINCT locality_add FROM table WHERE country_add = :country_add ORDER BY locality_add ASC");
$sqlQueryLocalityAdd->execute(array(':country_add' => $postCountryAdd));

echo '<option value="">Select locality</option>';
    foreach($sqlQueryLocalityAdd as $localityAddRow) {
        //while ($localityAddRow = $sqlQueryLocalityAdd->fetch()){
        echo '<option value="';
        echo $localityAddRow["locality_add"];
        echo '">';
        echo $localityAddRow["locality_add"];
        echo '</option>';
    }
}

如果我使用foreach($sqlQueryLocalityAdd as $localityAddRow),代码将停止响应。为什么我不能多次使用 foreach?请问怎么解决?

【问题讨论】:

  • 也许很有趣?指出可滚动游标在 mysql 中不可用。 stackoverflow.com/a/19076778/3184785.
  • 您的示例代码不会失败,因为它没有显示您有多个 foreach 块在彼此之后的情况——这就是人们感到困惑的原因。代码不会在整个结果集的第一次迭代中停止,否则您会尝试第二次完整迭代。

标签: php mysql pdo foreach


【解决方案1】:

$sqlQueryLocalityAdd 是一个对象,在这种情况下 - 我正在展示并且 OP 已使用 - 无法迭代。 (粗体以便@deceze 可以理解)。

不过,您可以在 foreach 循环中使用 fetchAll() 来实现此目的。

您的代码应如下所示:

[...]
    if($sqlQueryLocalityAdd->execute(array(':country_add' => $postCountryAdd)):
        foreach($sqlQueryLocalityAdd->fetchAll() as $row):
            echo $row['column'];
            [...]
        endforeach;
    endif;
[...]

Difference between an array and an Object

【讨论】:

  • 你可以foreach对象就好了,特别是当他们implement Traversable时,就像PDOStatement一样。
  • 从未见过这样做过,但这回答了他的问题,所以......我将“仅”编辑掉。 @deceze
  • 你还在说“不能迭代”,这显然是错误的。 OP 还(神秘地)说它可以工作一次(如果我正确解释了这个问题)。
  • 是的,OP 在哪里说过他使用了 cursor ?如果不更改他的 Prepare 语句,就无法迭代问题中的对象 OP。所以在这种情况下,我的回答是正确的。 @deceze
  • 它不能被迭代一次以上。可以被迭代一次
【解决方案2】:

问题是结果集只能迭代一次;然后它被耗尽,MySQL 将其丢弃,并且您无法再次对其进行迭代。

我实际上从未尝试过,但要创建一个可以迭代多次的结果集,您需要一个可滚动光标,您应该能够创建它因此:

$sqlQueryLocalityAdd = $dbh->prepare(..., [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);

理论上,您应该能够多次迭代结果。

如果这不起作用,请使用$sqlQueryLocalityAdd-&gt;fetchAll() 将数据提取到一个数组中,并根据需要尽可能频繁地对其进行迭代。事实上,这似乎是 MySQL 的唯一选择:https://stackoverflow.com/a/19076778/476

【讨论】:

  • 我终于明白了。 OP 令人困惑的部分只显示了一个 foreach 块。它并没有在语句生成的结果集的初始完整迭代的步骤中死亡,但它正在死亡,因为稍后的某个地方(未在帖子中显示)他正在尝试另一个 foreach 迭代。
  • @Ray 丁丁丁丁!我们赢了!
【解决方案3】:

$sqlQueryLocalityAdd 不是结果集,它是 PDOStatement 对象,您只能直接对其进行一次迭代(正如 deceze 明确指出的那样)。

execute() 语句在查询成功时返回 boolean true 或 false。

如果运行成功,您需要在查询后从中获取结果并迭代返回的数组:

   $success = $sqlQueryLocalityAdd->execute(array(':country_add' => $postCountryAdd));
   if($success) {

       $results = $sqlQueryLocalityAdd->fetchAll();

       foreach($results as $localityAddRow) {
           echo '<option value="';
            ....

生成的数组 $results 只是一个普通数组,因此您可以根据需要对其进行多次迭代。

注意:如果 execute() 返回 false,则查询有问题 - 成功运行的查询返回空结果集结果仍将导致 true

【讨论】:

  • PDOStatement implements Traversable,所以你可以直接迭代它!
  • @deceze 确实如此,好点。似乎无法找到有关它如何实现它的确切文档,因此不确定会发生什么。它在幕后做 fetchAll 吗?迭代结果是有道理的。
  • @deceze 如果那是真的,并且当传递给 foreach 时返回与 $row = $stmt-&gt;fetch() 完全相同的东西,示例代码将与 foreach 中的任何一个运行相同。你知道如果你从迭代中得到一个对象而不是一个数组吗?我
  • @deceze 我从来没有见过在结果集上使用直接迭代的例子,所以我想了解一下如何这样做,因为它看起来更优雅
  • @deceze 啊,我在另一个答案中看到了 cmets 的另一个线程。我现在明白了。顺便说一句,我的回答从未说过你不能遍历 PDOStatement。
猜你喜欢
  • 2013-11-01
  • 2019-11-23
  • 1970-01-01
  • 2014-02-02
  • 2014-02-11
  • 2015-09-15
  • 2021-12-13
  • 2014-02-06
  • 1970-01-01
相关资源
最近更新 更多