开发轻量ORM时,如何让PDO Fetch Class返回分组集合对象?
实现分组集合对象的方案
当然可以搞定这个需求!这其实是主流ORM的常规操作——用一个集合类把查询出来的模型实例统一封装起来,既能像数组一样方便遍历,还能加一堆实用的操作方法。
1. 先写一个基础的Collection类
这个类要实现PHP的核心接口,让它能像数组一样被遍历、统计,同时封装常用的集合操作:
class Collection implements \IteratorAggregate, \Countable { protected array $items = []; public function __construct(array $items = []) { $this->items = $items; } // 支持foreach遍历集合 public function getIterator(): \Traversable { return new \ArrayIterator($this->items); } // 支持用count()统计集合元素数量 public function count(): int { return count($this->items); } // 筛选符合条件的元素,返回新的Collection实例 public function filter(callable $callback): self { return new static(array_filter($this->items, $callback)); } // 对每个元素执行回调转换,返回新的Collection实例 public function map(callable $callback): self { return new static(array_map($callback, $this->items)); } // 获取指定索引的模型实例 public function get(int $index): mixed { return $this->items[$index] ?? null; } // 获取集合中的第一个模型实例 public function first(): mixed { return $this->items[0] ?? null; } // 把集合转换为关联数组(假设你的模型有toArray方法) public function toArray(): array { return array_map(fn($item) => $item->toArray(), $this->items); } }
2. 修改基础模型的查询方法
把原来返回数组的逻辑改成返回Collection实例,统一封装查询结果:
abstract class BaseModel { protected string $table; public static function all(): Collection { // 替换成你自己的数据库连接逻辑 $pdo = new PDO('mysql:host=localhost;dbname=your_database', 'username', 'password'); $stmt = $pdo->query("SELECT * FROM " . static::$table); // 用当前模型类实例化查询到的每一行数据 $models = $stmt->fetchAll(PDO::FETCH_CLASS, static::class); // 把模型数组包装成Collection对象返回 return new Collection($models); } }
3. 实际使用效果
现在你的所有模型查询都会返回统一的集合对象,用法非常灵活:
// 获取所有问题的集合 $questions = Question::all(); // 直接遍历集合中的模型实例 foreach ($questions as $question) { echo "问题标题:{$question->title}\n"; } // 统计集合总数 echo "共 " . count($questions) . " 个问题\n"; // 筛选出已发布的问题 $publishedQuestions = $questions->filter(fn($q) => $q->status === 'published'); // 获取第一个问题实例 $firstQuestion = $questions->first(); // 把集合转换为数组输出 print_r($publishedQuestions->toArray());
这么做的好处
- 统一返回类型:不管查询结果是空、单条还是多条,都返回Collection,不用再写
is_array()或者null判断的分支代码 - 可扩展的操作:把筛选、排序、映射等常用操作封装在Collection里,代码更简洁优雅
- 保留模型特性:集合里的每个元素都是完整的模型对象,能直接调用模型的方法和属性,不会丢失上下文
内容的提问来源于stack exchange,提问作者no.
相关产品推荐
相关产品推荐

