我正在开发一个PHP Web应用程序,用户可以创建到目的地的旅行,并邀请其他用户参加这些旅行。
我有Destinations
,Trips
和Users
的MySql表,以及一个名为Invites
的表来解决{{1}之间的多对多关系}和Users
。
对于这些表中的每一个,我在我的应用程序中创建了一个类(因此Trips
是一个类,Destinations
是一个类,等等)。我为这些类中的每一个编写了一个静态函数,它允许实例化对象并从MySQL查询中分配它们的属性(因此从Trips
查询返回的每一行都会导致实例化对象并分配属性)。
我正在尝试创建一个页面,我的用户可以在其中查看他们计划的所有行程的详细信息。此页面将显示目的地(来自SELECT *
),旅行详细信息(例如Destinations
的日期)以及他们邀请的用户的详细信息(例如来自Trips
的用户名)并将所有用户放入这个数据在一个html表中,每次旅行都是一行。
为实现这一目标,到目前为止,我一直在实例化与用户Users
,Trips
和user_id
相关的Destinations
Invites
。Trips
,以及与Users
相关的Invites
。然后我使用嵌套的foreach循环来显示这些,如下所示:
foreach($trips as $trip) {
foreach($invites as $invite) {
foreach($invited_users as $invited_user) {
if($invite->trip_id == $trip->id && $invite->guest_id == $invited_user->id) {
echo $invited_user->name;
} } } }
我能看到的是可怕的,无法做到这一点。
从阅读开始,我想我想使用MySQL加入4个表,然后只选择与我相关旅行相关的数据。但我不确定的是:
a)如何从MySQL结果中实例化对象并正确分配其属性?
b)即使完成了这项工作,如何避免昂贵的foreach
循环在正确的行程中显示正确的数据?
是否存在以面向对象的方式显示来自多个相关数据库表的数据的“最佳实践”方式?
答案 0 :(得分:2)
首先,“良好做法”是人们用来使偏见成为尊重的一种用语。最好问一下如何通过设计实现特定目标。
话虽如此:您偶然发现了将RDBMS映射到面向对象系统时常见的问题。谷歌“懒惰加载”进行了大量讨论。问题归结为你在任何时候加载了多少“关系”的问题。在您的示例中,旅行与目的地和用户相关联;加载“旅行”时,您是否还要加载目的地和用户?如果你这样做,你是否应该为用户加载其他信息(例如,他们正在进行的其他旅行?)。如果你这样做,你是否加载了用户所有旅行的旅行数据?等等 - 如果你不小心,你最终会加载整个数据库。
不加载所有相关实体的缺点是,如果一次加载每个对象的数据,性能会变得非常差。
有关我认为最佳做法的详细说明,请购买并阅读埃文斯的“域驱动设计”。
作为一种快捷方式,请考虑创建一个“存储库”图层,该图层知道如何将数据库记录映射到对象,并创建用于搜索所需内容的自定义方法。例如,您可以调用:
$repository::getTripsForUser($userID);
该方法将执行将4个表连接在一起的SQL查询,并将结果转换为对象树。
您可能希望利用其他人在解决此问题方面所做的工作;有许多“对象关系映射”框架可以解决这个问题。我认为陪审团仍然不清楚ORM解决方案是否让生活更轻松 - 但值得关注。
答案 1 :(得分:0)
我认为您使事情变得复杂,您不需要一次加载所有数据。
为什么要迭代所有行程,而您需要显示一个用户的行程?
使用OOP的一种天真但简单的方法:User
类,其中包含检索用户相关旅行的方法。
它可以返回一个Trip
数组,其中包含受邀用户的引用:
class User {
private $id;
public function __construct($id) {
$this->id = $id;
}
public function getTrips() {
$trips = array();
// Run your query using $this->id to build the WHERE clause
return $trips;
}
}
class Trip {
// Array of User objects invited to the trip
private $invited = array();
// Other methods here to add/retrieve invited users
}
$user = new User(1);
foreach ($user->getTrips() as $trip) {
// Do something with $trip
}
理想情况下,User
实例将存储在会话