如果我运行查询模拟器来:
SELECT * FROM user u
LEFT JOIN orders o ON o.user_id=u.id
LEFT JOIN payments p ON p.order_id=o.id
生成如下数据:
u.id, u.name, o.id, o.item, o.date_time, p.id, p.amount, p.date_time
99 jeff 17 spring 12-12-2012 12 10.99 13-12-2012
99 jeff 18 jam 12-12-2012 13 .99 16-12-2012
99 jeff 19 car 22-12-2012 14 1000 17-12-2012
99 jeff 19 car 22-12-2012 15 1000 18-12-2012
99 jeff 19 car 22-12-2012 16 1000 19-12-2012
所以用户杰夫有 3 个订单,他为他的车支付了 3 笔款项。
为 PHP 对象提供用户、订单和付款以及单个数据库查询 - 它们如何水合?我想看到伪代码,实际的php代码或我应该在:)上阅读的模式名称
因为没有答案,我将尝试描述我是如何解决这个问题的。这是一个玩具解决方案。
对数据库的查询是用一种我称之为QQL的小语言完成的,这是受Doctrine 2 DQL的启发。
SELECT *
FROM user
JOIN user order
JOIN order payment
WHERE user.name=?
这会被解析,并且可以构建一个 SQL 语句。解析树还用于将结果集映射回对象图。
每个模型都有与其他模型的"关系"的描述。所以用户有一对多的订单,订单有一对多的付款。描述位于包含模型名称、主键和前键名称的数组中。
要构建联接,请执行以下操作:
JOIN user order
检查 User 模型,获取表名"users",然后找到关系"order",获取 Order 表名称"orders"和联接键。使用它来构建:
JOIN orders o ON o.user_id=users.id
查询运行并返回结果以生成对象图后。我所做的是获取查询中使用的所有不同模型(在本例中为用户、订单和付款),然后为每一行补水
:// query DB and get results into an array called $rows
foreach ($rows as $row) {
foreach (array('User', 'Order', 'Payment') as $model) {
$o = new $model;
$o->hydrate($row);
// inspect primary key - have we got this object already? store or throw away
}
}
我的水合物方法非常薄(快速),因为构建的许多对象将是重复的并被删除。从我问题中的结果集中,您可以看到User('Jeff')将被构建5次,其中4次是重复的,将被丢弃。
读取结果后,有 3 个对象列表。用户、订单和付款。它们与解析树一起传递给图形生成器。
图形生成器使用分析树来查看关系。从"根"模型(由"FROM 用户"确定)开始,检查解析的 QQL 以查找请求的 JOIN(User->id TO Order->user_id)将订单添加到用户>订单数组。然后,它对(订单>ID TO Payment->order_id)执行相同的操作。
结果是:
$user->name == 'jeff'
$user->orders[0]->item == 'spring'
$user->orders[1]->item == 'jam'
$user->orders[2]->item == 'car'
$user->orders[2]->payments[2]->date_time == '19-12-2012'
我最终得到了四个主要类,ORM,所有模型扩展的Model_Base(这确保每个模型都有一个"表名","列"和"关系"),一个QQLParser和一个图形生成器。ORM级是迄今为止最大的,有近200条线路。
结论。它有效。这感觉类似于原则2,(所以我最终过渡到使用原则2会不那么痛苦)。它可能会更有效率。分析在几千个对象中读取的测试页面的结果,到目前为止,最慢的部分是SQL查询(3ms)和释放mysqli结果(1ms),包括模型类(0.7ms)。写它很有趣,只花了一天时间。
PDO允许自动水化对象,例如。 PDOStatement::fetchObject