2013-03-23 112 views
2

我很新的PHP面向對象編程,以便在想,如果我能我創建了一個數據庫對象上得到一些好的建議。PDO和PHP的OOP代碼意見

我打電話給db並將我的類包含到每個頁面加載中,並啓動數據庫對象using $db = new db。然後,我根據自己想要做的事情,針對每個可能需要的操作(從數據庫構建菜單,獲取登錄信息等)調用此方法。

它需要它的第一個參數作爲與查詢?符號作爲我想要綁定的值的替換,第二個參數是在數組中將值綁定到它的值,然後再通過prepared_statement方法循環,​​第三個參數是類型(FETCH_ARRAY返回SELECT語句行的數組, NUM_ROWS返回受影響的行數,INSERT返回最後插入的ID)。

的我怎麼會調用這個函數下面是一個例子:

$db->prepared_execute("SELECT * FROM whatever WHERE ? = ? ", array('password', 'letmein'), NUM_ROWS); 

第二個和第三個參數是可選的,如果沒有被綁定的參數或無需返回。

由於我是新來OOP,我發現很難讓我的頭周圍什麼時候正確地使用,什麼是公共的,私人的,靜態函數/變量和設計模式(辛格爾頓等)。

我已經閱讀了很多教程,只要我有,但我覺得現在我需要在這裏獲得進一步的答案或建議下一步與OOP和我已經建成的類。

它的工作原理,因爲它是這對我來說是除了任何錯誤處理,我將在明年增加一個很好的起點,但我要確保我不會在這裏做任何明顯的設計錯誤。

該類的代碼如下:

class db { 

var $pdo; 

public function __construct() { 

$this->pdo = new PDO('mysql:dbname=' . DB_NAME . ';host=' . DB_HOST . ';charset=utf8', DB_USER, DB_PASS); 
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

} 

public function prepared_execute($query, $bind_values = null, $type = null) { 

$preparedStatement = $this->pdo->prepare($query); 

if($bind_values) { 

$i = 1; 

foreach($bind_values as $bind_value) { 

$preparedStatement->bindValue($i, $bind_value); 

$i++; 

} } 

$preparedStatement->execute(); 

if( $type == FETCH_ARRAY) { return $preparedStatement->fetchAll(); } 

elseif($type == NUM_ROWS) { return $preparedStatement->rowCount();  } 

elseif($type == INSERT ) { return $this->pdo->lastInsertId();   } 

else{ return true; } 

} 

回答

1

您的代碼有點過時。您應該使用visibility keywords之一而不是var來聲明您的屬性。在這種情況下,您可能希望使用protected,以便它不能從類外部修改,但是以便任何未來的子類都可以在內部對其進行修改。你也可能想要添加一個getter,以防你需要直接與PDO一起工作(你將會 - 在我的例子下面看到我的最終陳述)。

其糟糕的硬編碼PDO你在課堂上的連接信息。您應該將這些參數作爲參數傳入,與直接使用PDO時相同。我還將添加傳遞預配置PDO實例的功能。

雖然不是必需的,它是一個好主意,以符合PSR-0 through PSR-2;就您的情況而言,即時講述類和方法的命名,這應該是camelCase和類的第一個字符應該是資本。與此相關的是,你的代碼格式也很糟糕,尤其是你的塊語句......如果這是複製和粘貼的問題,然後忽略該評論。

所以總的來說,我會重構代碼看起來是這樣的:

class Db { 

    protected $pdo; 

    public function __construct($dsn, $user, $pass, $options = array()) { 

    if($dsn instanceof PDO) { 
     // support passing in a PDO instance directly 
     $this->pdo = $dsn; 

    } else { 

     if(is_array($dsn)) { 
     // array format 
     if(!empty($options)) { 
      $dsn['options'] = $options; 
     } 

     $dsn = $this->buildDsn($options); 
     } else { 
     // string DSN but we need to append connection string options 
     if(!empty($options)) { 
      $dsn = $this->buildDsn(array('dsn' => $dsn, 'options' => $options)); 
     } 
     } 

     // otherwise just use the string dsn 
     // ans create PDO 

     $this->pdo = new PDO($dsn, $user, $pass); 
    } 

    // set PDO attributes 
    $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 
    $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    } 

    public function getConnection() 
    { 
    return $this->pdo; 
    } 

    protected function buildDsn($options) { 

    if($isDbParts = isset($options['dbname'], $options['hostname']) || !($isDsn = isset($option['dsn']))) { 
     throw new Exception('A dsn OR dbname and hostname are required'); 
    } 

    if($isDsn === true) { 
     $dsn = $options['dsn']; 
    } else if { 
     $format = '%s:dbname=%s;host=%s'; 
     $driver = isset($options['dbtype']) ? $options['dbtype'] : 'mysql'; 
     $dsn = sprintf($format, $options['dbtype'], $options['dbname'], $options['host']); 
    } 

    if(isset($options['options'])) { 
     $opts = array(); 

     foreach($options['options'] as $name => $value) { 
     $opts[] = $name . '=' . $value; 
     } 

     if(!empty($opts)) { 
     $dsn .= ';' . implode(';', $opts); 
     } 
    } 

    return $dsn; 
    } 

    public function preparedExecute($query, $bind_values = null, $type = null) { 

    $preparedStatement = $this->pdo->prepare($query); 

    if($bind_values) { 

     $i = 1; 

     foreach($bind_values as $bind_value) { 

     $preparedStatement->bindValue($i, $bind_value); 

     $i++; 
     } 
    } 

    $preparedStatement->execute(); 

    if($type == FETCH_ARRAY) { 
     return $preparedStatement->fetchAll(); 
    } 
    elseif($type == NUM_ROWS) { 
     return $preparedStatement->rowCount();  
    } 
    elseif($type == INSERT ) { 
     return $this->pdo->lastInsertId();   
    } 
    else { 
     return true; 
    } 

    } 
} 

最後,除非這只是爲了教育目的我不會這麼做。有很多不同的查詢有不同的部件組件,這些部件組件在這裏沒有考慮到,所以在某些時候這不會支持您需要它做的事情。相反,我會使用Doctrine DBAL,Zend_Db或類似的東西,通過它的API來支持更大的查詢複雜性。總之,不要重新發明輪子。

+0

非常感謝你的迴應!我會花時間仔細閱讀這些內容,並檢查您發佈的鏈接,如果我有任何問題,請告訴我們,但非常感謝您的反饋意見,這正是我一直在尋找的內容。 – 2013-03-23 01:31:11

0

我已經開發了類似的東西,它可以幫助你。

public function select($sql, $array = array(), $fetchMode = PDO::FETCH_ASSOC){  
    $stmt = $this->prepare($sql); 

    foreach ($array as $key => $value){ 
     $stmt->bindValue("$key", $value); 
    } 

    $stmt->execute(); 
    return $stmt->fetchAll(); 
} 

public function insert($table, $data){ 
    ksort($data); 

    $fieldNames = implode('`,`', array_keys($data)); 
    $fieldValues = ':' .implode(', :', array_keys($data)); 

    $sql = "INSERT INTO $table (`$fieldNames`) VALUES ($fieldValues)"; 

    $stmt = $this->prepare($sql); 

    foreach ($data as $key => $value){ 
     $stmt->bindValue(":$key", $value); 
    } 

    $stmt->execute(); 
} 
+0

感謝您發佈您的代碼,但我的問題的真正意義在於獲得有關我的代碼的正確/錯誤的建議,併爲真正理解OOP提供進一步的建議/幫助。我試圖讓我的db類只使用單一方法,以便在編寫項目時更容易記住結構,因爲我用它作爲最後一個不同類型的所有SQL語句(SELECT,INSERT,DELETE等)。參數。 – 2013-03-23 00:20:52