本文目录导读:

在PHP中处理数据库结果集时,迭代器模式是一种非常优雅且内存高效的方式,以下是几种实现数据库结果集迭代器的方法:
使用内置的PDOStatement迭代器
PDOStatement已经内置了Iterator接口,可以直接遍历:
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
// 使用PDOStatement直接迭代(已实现Iterator接口)
$stmt = $pdo->query('SELECT * FROM users');
foreach ($stmt as $row) {
echo $row['name'] . "\n";
}
自定义数据库结果集迭代器类
创建一个专门的迭代器类,提供更灵活的控制:
class DatabaseResultIterator implements Iterator {
private $statement;
private $currentRow;
private $position = 0;
private $rowCount = 0;
private $key = 0;
public function __construct(PDOStatement $statement) {
$this->statement = $statement;
$this->rowCount = $statement->rowCount();
}
// 返回当前行的数据
public function current() {
return $this->currentRow;
}
// 返回当前键
public function key() {
return $this->key;
}
// 移动到下一行
public function next() {
$this->key++;
$this->currentRow = $this->statement->fetch(PDO::FETCH_ASSOC);
}
// 重置迭代器
public function rewind() {
if ($this->position > 0) {
throw new Exception('不能重置已开始的迭代器');
}
$this->key = 0;
$this->currentRow = $this->statement->fetch(PDO::FETCH_ASSOC);
$this->position++;
}
// 检查当前位置是否有效
public function valid() {
return $this->currentRow !== false;
}
}
使用生成器(更简单的方法)
PHP的生成器是更简洁的实现方式:
function fetchRows(PDOStatement $stmt) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
yield $row;
}
}
// 使用示例
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->query('SELECT * FROM large_table');
foreach (fetchRows($stmt) as $row) {
// 处理每一行
processRow($row);
}
内存优化的迭代器实现
对于大型数据集,这种方法特别有用:
class LargeDatasetIterator implements Iterator {
private $connection;
private $query;
private $params;
private $currentRow;
private $key = 0;
private $valid = false;
public function __construct(PDO $connection, $query, $params = []) {
$this->connection = $connection;
$this->query = $query;
$this->params = $params;
}
public function rewind() {
$this->key = 0;
$stmt = $this->connection->prepare($this->query);
$stmt->execute($this->params);
$this->currentRow = $stmt->fetch(PDO::FETCH_ASSOC);
$this->valid = ($this->currentRow !== false);
}
public function current() {
return $this->currentRow;
}
public function key() {
return $this->key;
}
public function next() {
$this->key++;
// 这里需要重新执行或者使用游标
if ($this->currentRow !== false) {
$stmt = $this->connection->prepare($this->query);
$stmt->execute($this->params);
$this->currentRow = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_ABS, $this->key);
}
}
public function valid() {
return $this->valid;
}
}
使用试用的完整示例
<?php
class DatabaseResultSet {
private $pdo;
private $query;
private $params;
private $statement;
private $data = [];
private $position = 0;
public function __construct(PDO $pdo, $query, $params = []) {
$this->pdo = $pdo;
$this->query = $query;
$this->params = $params;
$this->execute();
}
private function execute() {
$this->statement = $this->pdo->prepare($this->query);
$this->statement->execute($this->params);
$this->data = $this->statement->fetchAll(PDO::FETCH_ASSOC);
}
public function toIterator() {
return new ArrayIterator($this->data);
}
public function toGenerator() {
foreach ($this->data as $row) {
yield $row;
}
}
public function getCount() {
return count($this->data);
}
}
// 使用示例
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$result = new DatabaseResultSet($pdo, 'SELECT * FROM users WHERE active = ?', [1]);
// 方式1:使用ArrayIterator
foreach ($result->toIterator() as $row) {
echo $row['name'] . "\n";
}
// 方式2:使用生成器
foreach ($result->toGenerator() as $row) {
echo $row['name'] . "\n";
}
?>
内存效率比较
| 方法 | 内存使用 | 适用场景 |
|---|---|---|
| fetchAll() | 高(一次性加载所有数据) | 小数据集 |
| PDOStatement迭代 | 低(逐行读取) | 大数据集 |
| 生成器 | 极低(即时生成) | 大数据集、流式处理 |
| 自定义迭代器 | 低(可控) | 需要特殊控制逻辑 |
最佳实践建议
- 小型数据集:直接使用
fetchAll()简单方便 - 大型数据集:使用PDOStatement或生成器逐行处理
- 需要随机访问:使用
fetchAll()配合ArrayIterator - 流式处理:使用生成器实现流式处理
选择哪种方法取决于你的具体需求:数据量大小、是否需要随机访问、内存限制等因素。