2017-05-21 49 views
0

這是我第一次在PHP中創建一個面向對象的站點和一個關於構造函數的問題。在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

最好的做法是分開你的邏輯代碼,讓你的方法有一個工作,要麼是查詢或其他任何東西 – hassan

+0

謝謝,現在編輯。 –

+1

https://en.wikipedia.org/wiki/SOLID_(object-oriented_design),這是用於對象的方法 – hassan

回答

1

而且它也應儘量避免使用魔法getter和setter方法。單身人士也是如此。

構造函數實際上不應該包含任何邏輯,因爲它使得代碼很難測試。相反,您的類構造函數應該將連接作爲參數,並以單獨的方法執行邏輯。有點兒像這樣:

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

在這種情況下,映射類把你的實體,採用的是吸氣提取用戶名,調用SQL,然後把數據在人物對象。後來,當你更熟悉OOP時,你也將學會在必要時能夠在同一個實體上調用多個映射器(例如,你可以設置它,以便有一個單獨的緩存映射器和db分離..你首先調用緩存映射器,如果失敗,則調用db映射器)。

+0

這非常感謝! –

0

這個缺點是你的'Character'類的構造函數會緊密地耦合到你的數據庫。這意味着除了從數據庫獲取數據之外,沒有其他方式可以初始化您的「字符」。您將無法使用其他來源(例如XML文件)對其進行初始化,或者爲了進行單元測試而將其初始化爲測試數據。

我會推薦的是將查詢分隔成類似'InitializationProvider'(這只是一個例子,因爲我不確定你的應用程序的邏輯)。然後你可以有不同類型的InitializationProviders,比如DBInitializationProvider,XMLInitializationProvider等等,它們將被動態地注入到你的Character類中。

這取決於你,雖然如果這種靈活性將在未來需要。

相關問題