PHP数据库结果集迭代器

wen PHP项目 1

本文目录导读:

PHP数据库结果集迭代器

  1. 使用内置的PDOStatement迭代器
  2. 自定义数据库结果集迭代器类
  3. 使用生成器(更简单的方法)
  4. 内存优化的迭代器实现
  5. 使用试用的完整示例
  6. 内存效率比较
  7. 最佳实践建议

在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迭代 低(逐行读取) 大数据集
生成器 极低(即时生成) 大数据集、流式处理
自定义迭代器 低(可控) 需要特殊控制逻辑

最佳实践建议

  1. 小型数据集:直接使用fetchAll()简单方便
  2. 大型数据集:使用PDOStatement或生成器逐行处理
  3. 需要随机访问:使用fetchAll()配合ArrayIterator
  4. 流式处理:使用生成器实现流式处理

选择哪种方法取决于你的具体需求:数据量大小、是否需要随机访问、内存限制等因素。

抱歉,评论功能暂时关闭!