【问题标题】:Is it possible to rewind a PDO result?是否可以回退 PDO 结果?
【发布时间】:2010-09-21 15:38:49
【问题描述】:

我正在尝试为 PDO 语句的结果编写一个迭代器,但我找不到任何方法可以倒回到第一行。我想避免调用 fetchAll 并存储所有结果数据的开销。

// first loop works fine
foreach($statement as $result) {
    // do something with result
}

// but subsequent loops don't
foreach($statement as $result) {
    // never called 
}

有没有办法重置语句或寻找第一行?

【问题讨论】:

    标签: php iterator pdo


    【解决方案1】:

    很久以前问过,但目前有另一种解决方案。

    方法PDOStatement::fetch() 可以接收第二个参数,即光标方向,带有PDO::FETCH_ORI_* 常量之一。这些参数仅在 PDOStatement 使用属性 PDO::ATTR_CURSOR 作为 PDO::CURSOR_SCROLL 创建时才有效。

    这样你可以如下导航。

    $sql = "Select * From Tabela";
    $statement = $db->prepare($sql, array(
        PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
    ));
    $statement->execute();
    $statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_NEXT);  // return next
    $statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR); // return previous
    $statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_FIRST); // return first
    $statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_LAST);  // return last
    $statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_ABS, $n); // return to $n position
    $statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_REL, $n); // return to $n position relative to current
    

    docsPDO predefined constants 中的更多信息。

    注意:使用PDO::FETCH_BOTH 因为是默认设置,只需为您的项目自定义即可。

    【讨论】:

      【解决方案2】:

      参见slide 31 from this presentation,如果它适用于缓冲查询,您可以执行$statement->rewind()。如果你使用mysql,你可以使用PDO_MYSQL_ATTR_USE_BUFFERED_QUERY模拟缓冲查询:

      $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
      

      @NoahGoodrich 向您指出 spl。这是一个始终有效的示例:

      $it = new ArrayIterator($stmt->fetchAll());
      

      【讨论】:

        【解决方案3】:

        我编写的这个小类包装了一个 PDOStatement。它只存储获取的数据。如果这不起作用,您可以移动缓存以读取和写入文件。

        // Wrap a PDOStatement to iterate through all result rows. Uses a 
        // local cache to allow rewinding.
        class PDOStatementIterator implements Iterator
        {
            public
                $stmt,
                $cache,
                $next;
        
            public function __construct($stmt)
            {
                $this->cache = array();
                $this->stmt = $stmt;
            }
        
            public function rewind()
            {
                reset($this->cache);
                $this->next();
            }
        
            public function valid()
            {
                return (FALSE !== $this->next);
            }
        
            public function current()
            {
                return $this->next[1];
            }
        
            public function key()
            {
                return $this->next[0];
            }
        
            public function next()
            {
                // Try to get the next element in our data cache.
                $this->next = each($this->cache);
        
                // Past the end of the data cache
                if (FALSE === $this->next)
                {
                    // Fetch the next row of data
                    $row = $this->stmt->fetch(PDO::FETCH_ASSOC);
        
                    // Fetch successful
                    if ($row)
                    {
                        // Add row to data cache
                        $this->cache[] = $row;
                    }
        
                    $this->next = each($this->cache);
                }
            }
        }
        

        【讨论】:

          【解决方案4】:

          我很确定这是依赖于数据库的。正因为如此,这是你应该尽量避免的事情。但是,我认为您可以通过启用buffered queries 来实现您想要的。如果这不起作用,您始终可以使用fetchAll 将结果拉入数组中。这两种解决方案都会影响您的应用程序性能,因此如果结果集很大,请三思而后行。

          【讨论】:

            【解决方案5】:

            您可能希望了解一些 PHP SPL 类,这些类可以扩展以提供对对象的类似数组的访问。

            【讨论】:

              猜你喜欢
              • 2012-02-08
              • 2023-04-10
              • 1970-01-01
              • 2018-03-08
              • 2016-03-23
              • 2020-01-06
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多