2015-04-23 30 views
0

每当我创建一个新的OOP应用程序时,我都会与这个问题纠缠在一起。假设这将成为一个不断增长的大中型网站,那么实现选择嵌套在另一个对象中的对象的正确方法是什么(在这种情况下,实现查询匹配信息的最佳方式是什么)。PHP/MySql - 使用嵌套对象查询对象的最佳方法

比方说,我有这样的:

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是更DB密集(想,如果我想在一个团队中显示的足球运动员名单,这是1个呼叫团队+ 1个调用来获取所有标识的球员对球队的+对于每个玩家对象53个更多的呼叫),但更容易管理,选项2更少的数据库连接(1呼叫队,1呼叫所有球员),但更难以维护。那么实现这一点的正确方法是什么?还是有更好的方法?

+0

如果你使用[prepared statement](https://php.net/manual/en/mysqli.quickstart.prepared-statements.php)并重用SELECT语句,我认为选项1是可以接受的。 – Passerby

+0

感谢您的回复。如果我在我的getSportsTeam()函数中使用准备好的语句,但是该函数连续被多次调用,那么这仍然利用准备好的语句吗?每次调用函数时都不会再次准备它吗? – Felix

+0

您需要缓存准备好的语句变量,并重用该变量。我通常通过构建处理缓存的自定义数据库类来实现这一点。 – Passerby

回答

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“变量”的全局命名空间下)这样做:

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

它是由你来选择合适的方式,适合你的需要。

+0

谢谢,帮助! – Felix

+0

通过使用单例使一个类依赖于另一个类是否正确?您可以通过在第一个类的构造函数中传递DB对象来进行显式依赖。 – denied

+0

@denied我从来没有说过对单身人士使用依赖。你误读了“或”阶段? – Passerby