PHP/MySql - 使用嵌套对象查询对象的最佳方法

Posted

技术标签:

【中文标题】PHP/MySql - 使用嵌套对象查询对象的最佳方法【英文标题】:PHP/MySql - Optimal way to querying an object with nested objects 【发布时间】:2015-04-23 02:35:16 【问题描述】:

每次制作新的 OOP 应用程序时,我都会为这个问题而苦恼。假设这将成为一个不断增长的中大型站点,那么实现选择嵌套在另一个对象中的对象的正确方法是什么(在这种情况下,实现对匹配信息查询的最佳方法是什么)。

假设我有这个:

Class SportsTeam 
   protected $teamId;
   protected $teamName;
   protected $teamLocation;


Class Matchup 
   protected $matchupId;
   protected $date;
   protected $time;
   protected $homeTeamId;
   protected $awayTeamId;
   protected $homeTeam; //SportsTeam object
   protected $awayTeam; //SportsTeam object


Class SportsTeamDao 
    public function getSportsTeam($teamId)  //Get SportTeam info 


Class MatchupDao 
    public function getMatchup($matchupId)  //Get Matchup info 

选项 1:选择比赛对象本身,并在比赛对象内调用 homeTeam 对象的 get 方法和 awayTeam 对象中的调用,以根据需要获取整个 SportsTeam 对象,这样如果我向 SportsTeam 添加属性稍后的对象(例如 teamLogo)它们可以访问到我使用 matchup 对象的位置。

Class Matchup 
   protected $matchupId;
   protected $date;
   protected $time;
   protected $homeTeamId;
   protected $awayTeamId;
   protected $homeTeam; //SportsTeam object
   protected $awayTeam; //SportsTeam object

   //Getters and setters for matchupId, date, time, homeTeamId, awayTeamId
   public function getHomeTeam() 
      $this->homeTeam = SportsTeamDao::getSportsTeam($this->homeTeamId);
      return $homeTeam;
   

   public function getAwayTeam() 
      $this->awayTeam = SportsTeamDao::getSportsTeam($this->awayTeamId);
      return $awayTeam;
   


Class SportsTeamDao 
    public function getSportsTeam($teamId)  //Get SportTeam info 


Class MatchupDao 
    public function getMatchup($matchupId) 
        $query = "SELECT matchupId, date, time, hometeamid, awayteamid WHERE matchupId = $matchupId LIMIT 1"; //I'd parameterize it of course
    

选项 2:选择连接中匹配可能需要的所有详细信息,因此我只访问数据库一次。缺点是如果我稍后将属性添加到 SportsTeam,我必须记住将其添加到我的选择语句中,用于 SportsTeam 和 Matchup 以及需要使用这些新属性的任何其他地方。

Class SportsTeam 
   protected $teamId;
   protected $teamName;
   protected $teamLocation;


Class Matchup 
   protected $matchupId;
   protected $date;
   protected $time;
   protected $homeTeamId;
   protected $awayTeamId;
   protected $homeTeam; //SportsTeam object
   protected $awayTeam; //SportsTeam object


Class SportsTeamDao 
    public function getSportsTeam($teamId)  //Get SportTeam info 


Class MatchupDao 
    public function getMatchup($matchupId) 
        $query = "SELECT M.matchupid, M.date, M.time, M.homeTeamId, M.awayTeamId, HT.teamName AS homeN, HT.teamLocation AS homeL, AT.teamName AS awayN, AT.teamLocation AS awayL FROM matchups M LEFT JOIN sportsteam HT ON M.hometeamid = HT.teamid LEFT JOIN sportsteam AT ON M.awayteamid = AT.teamid WHERE matchupid = $matchupid LIMIT 1";
    //Set matchup properties and hometeam object properties and awayteam object properties
    

我的困境是选项 1 更密集(想想如果我想显示一个球队中的足球运动员列表,它是 1 次调用球队 + 1 次调用来获取球队中所有球员的 ID + 53 次调用一个对于每个玩家对象)但更易于管理,选项 2 是更少的数据库连接(1 次调用团队,1 次调用所有玩家)但更繁琐的维护。那么实现这个的正确方法是什么,或者有第三种更好的方法吗?

【问题讨论】:

如果你使用prepared statement并重用SELECT语句,我认为选项1是可以接受的。 感谢您的回复。这是后续行动,如果我在 getSportsTeam() 函数中使用准备好的语句,但该函数连续多次调用,那是否仍然利用准备好的语句?不是每次调用函数都要重新准备吗? 您需要缓存准备好的语句变量,并重用该变量。我通常通过构建一个处理缓存的自定义 DB 类来做到这一点。 有趣的想法,能给我举个例子吗?就像这是一个父类,每个准备好的语句都有一个变量或更复杂的东西? 【参考方案1】:

评论太长了,来个答案吧。

选项 1 “结构上”更好。您主要关心的是繁重的数据库连接,如果您使用 prepared statement 并重用 SELECT 语句,可以在一定程度上对其进行优化。

这是我通常做的以确保语句重用(只是一个演示;实际代码中可能有更多逻辑):

class DB

    protected $statements=[];
    public function prepare($query)
    
        if(empty($this->statements[$query]))
        
            $this->statements[$query]=$mysqli->prepare($query);
        
        return $this->statements[$query];
    

因此,每当您准备查询时,数据库实例都会检查该查询之前是否已准备好,如果已准备好,则返回该语句而不是再次重新准备。

下一步是让您的类依赖于您的 DB 类。您可以使用 Singleton(全局命名空间下的静态数据库“变量”)来做到这一点:

class Singleton

    protected static $db;
    public static function getDB()
    
        if(empty(self::$db))
        
            self::$db=new DB(/*...*/);
        
        return self::$db;
    

或类似的东西:

class Car

    public function __construct(DB $db);

您可以根据自己的需要选择合适的方式。

【讨论】:

使用单例使一个类依赖另一个类是否正确?您可以通过在第一类的构造函数中传递 DB 对象来进行显式依赖。 @denied 我从来没有说过要对单例使用依赖。您是否误读了“或”阶段? 糟糕,我非常想开始一场圣战,以至于我什至没有读到你的答案:) 抱歉)

以上是关于PHP/MySql - 使用嵌套对象查询对象的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

使用 php mysql 创建嵌套的 json 对象

Swift NSFetchedResultsController 嵌套对象的最佳实践

将具有嵌套对象的对象保存到文件的最佳方法?

从嵌套的 javascript 对象中删除属性的最佳方法是啥?

将嵌套对象数组转换为对象数组的最佳方法

Vue:访问错误对象中可能存在的嵌套属性的最佳方法