这是我第一次在PHP中创建面向对象的站点以及有关构造函数的问题。
我有一个用户登录后生成的角色类。角色对象将保存游戏的所有用户数据。
我的问题是关于构造函数/实例化类。可以在类构造函数中运行查询,就像我在附加的代码中一样吗?
目前传入的参数只是登录期间获取的用户名,也就是在查询中运行的用于获取角色信息的用户名。
这是可行的还是最佳做法是在构造或类之外运行查询并将参数传递给类构造函数?
只是想确保我没有忽略我当前代码的任何潜在问题 - 只要考虑异常就可以将查询保留在构造函数中,不是吗?
<?php
include $_SERVER['DOCUMENT_ROOT']."/rx/includes/classes/connection.php";
class Character {
private $charid;
private $userid;
private $username;
private $class;
private $exp;
private $money;
private $attack;
private $defense;
private $hp;
private $turns;
function __construct($data){
$pdo = Connection::getInstance();
try {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$char = $pdo->prepare("SELECT users.userid, users.username, characters.charid, characters.money, characters.attack, characters.defense, characters.class, characters.hp, characters.userid, characters.turns, characters.exp
FROM characters
JOIN users ON users.userid=characters.userid
WHERE username=?");
$char->execute(array($data));
$res = $char->fetchAll(PDO::FETCH_ASSOC);
$this->charid = $res[0]['charid'];
$this->userid = $res[0]['userid'];
$this->username = $res[0]['username'];
$this->class = $res[0]['class'];
$this->exp = $res[0]['exp'];
$this->money = $res[0]['money'];
$this->attack = $res[0]['attack'];
$this->defense = $res[0]['defense'];
$this->hp = $res[0]['hp'];
$this->turns = $res[0]['turns'];
}
catch (Exception $e){
echo $e;
}
}
public function __get($property) {
if (property_exists($this, $property)) {
return $this->$property;
}
}
public function __set($property, $value) {
if (property_exists($this, $property)) {
$this->$property = $value;
}
return $this;
}
}
答案 0 :(得分:1)
没有
同时建议避免使用魔术套装和吸气剂。单身人士也一样。
构造函数实际上不应包含任何逻辑,因为它使代码很难测试。相反,您的类构造函数应该将连接作为参数,并在单独的方法中执行逻辑。有点像这样:
class Character
{
private $connection;
public function __construct(\PDO $pdo)
{
$this->connection = $pdo;
}
public function populateByUsername($data)
{
// come code
$statement = $pdo->prepare("SELECT us ....");
$statement->execute(array($data));
$data = $char->fetchAll(PDO::FETCH_ASSOC);
// more code
}
}
为了进一步改进代码,我建议实际上将SQL代码与实体的逻辑分开(在你的例子中 - 字符)。最好的方法是使用data mapper模式 - 它基本上意味着你有两个类 - 一个用于实体,一个用于sql部分。最终看起来像这样:
$char = new Character;
$char->setUsername($username);
$mapper = new CharacterMapper($pdo);
$mapper->fetchByUsername($char);
在这种情况下,mapper类占用您的实体,使用getter提取用户名,调用SQL然后将数据放入角色对象中。稍后,当您更熟悉OOP时,您还将学习能够在必要时在同一实体上调用多个映射器(例如,您可以设置它以便有一个单独的缓存映射器和db分离..先调用缓存映射器,如果失败,则调用db mapper)。
答案 1 :(得分:0)
这样做的缺点是你的'Character'类构造函数会与你的数据库紧密耦合。这意味着除了从数据库获取数据之外,没有其他方法可以初始化您的“字符”。您将无法使用其他来源(例如XML文件)对其进行初始化,或者使用测试数据对其进行初始化以进行单元测试。
我建议将查询分成类似'InitializationProvider'的东西(这只是一个例子,因为我不确定你的应用程序的逻辑)。然后你可以有不同类型的InitializationProviders,如DBInitializationProvider,XMLInitializationProvider等,它们将动态注入你的Character类。
如果将来需要这种灵活性,这取决于你。