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

时间:2015-04-23 02:35:17

标签: php mysql oop query-optimization

每次我制作一个新的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)可以访问我使用匹配对象的位置。

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次召唤以获得所有身份的球员在团队中,为每个玩家对象增加了53个调用,但更容易管理,选项2是更少的数据库连接(1个团队调用,1个所有玩家调用),但维护起来更乏味。那么实现这个的正确方法是什么,还是有第三种更好的方法呢?

1 个答案:

答案 0 :(得分: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];
    }
}

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

下一步是让你的类依赖于你的数据库类。您可以通过使用Singleton(全局命名空间下的静态DB“变量”)来完成此操作:

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);
}

由您自己选择适合您需求的方式。