Я пытаюсь написать итератор для результатов из инструкции 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 }
Есть ли способ переустановки заявления или поиска первой строки?
Я уверен, что это зависит от базы данных. Из-за этого вы должны избегать этого. Однако, я думаю, вы можете достичь того, чего хотите, включив буферизованные запросы . Если это не сработает, вы всегда можете вывести результат в массив с помощью fetchAll
. Оба решения влияют на производительность ваших приложений, поэтому дважды подумайте об этом, если набор результатов большой.
Этот маленький класс, который я написал, обертывает 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); } } }
см. слайд 31 из этой презентации , вы можете сделать $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());
Вероятно, вы захотите взглянуть на некоторые из классов PHP SPL, которые могут быть расширены для обеспечения доступа к объектам, подобным массиву.
Спрошено давно, но в настоящее время есть еще одно решение.
Метод 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
Дополнительная информация в документах и предопределенных константах PDO .
Примечание: используемый PDO::FETCH_BOTH
поскольку он по умолчанию, просто настройте его для своего проекта.