2011-04-08 54 views
0

我想通过PHP中的OOP来管理我的数据库连接和查询,我对它并不擅长。我知道我正在重新发明轮子,但这就是我喜欢的方式:)php数据库类

我使用了三个类,其中一个是SQL parser我还没有自己做过。我的实现在创建新连接时返回一个对象。程序员应该通过这个数据库对象创建一个新的查询实例(每个SQL语句一个实例)。我的问题是:如何让我的查询类只能从数据库类中调用?

我正在粘贴我的课程简历和下面的实施。随时让我知道它有多糟糕。谢谢!

class genc_db_parser 
    { 
     /* See at http://www.tehuber.com/article.php?story=20081016164856267 
     returns an array with indexed values ('select','from','where','update',...) when they are available */ 
    } 
    class genc_database 
    { 
     public $db; /* The database connection */ 
     public $signature; /* Unique signature for the connection */ 
     public static $instances = array(); /* Array of references to connection */ 
     public static function error($e,$sql) 
     { 
      /* Errors */ 
     } 
     private static function singleton($cfg,$inst) 
     { 
      $signature = sha1(serialize($cfg)); 
      if (isset($cfg['host'],$cfg['user'],$cfg['pass'],$cfg['db'],$cfg['engine'])) 
      { 
       foreach (self::$instances as $obj) 
       { 
        if ($obj->signature == $signature) 
         return $obj->db; 
       } 
       try 
        { $db = new PDO($cfg['engine'].':host='.$cfg['host'].';dbname='.$cfg['db'], $cfg['user'], $cfg['pass']); } 
       catch (PDOException $e) 
        { self::error($e); } 
       if ($db) 
       { 
        $t = self::$instances; 
        array_push($t,$inst); 
        return $db; 
       } 
      } 
      return false; 
     } 
     function __construct($cfg=array()) 
     { 
      if (isset($cfg['host'],$cfg['user'],$cfg['pass'],$cfg['db'])) 
       $cfg['engine'] = isset($cfg['engine']) ? $cfg['engine'] : 'mysql'; 
      else 
       $cfg = array(
        'host' => GEN_DB_HOST, 
        'user' => GEN_DB_USER, 
        'pass' => GEN_DB_PASS, 
        'db' => GEN_DATABASE, 
        'engine' => GEN_DB_ENGINE 
       ); 
      if (isset($cfg['host'],$cfg['user'],$cfg['pass'],$cfg['db'],$cfg['engine'])) 
      { 
       if ($this->db = self::singleton($cfg,$this)) 
       { 
        $this->signature = sha1(serialize($cfg)); 
        $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
        if ($cfg['engine'] == 'mysql') 
        { 
         $this->db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true); 
         $this->db->exec('SET CHARACTER SET utf8'); 
        } 
       } 
      } 
     } 
     public function query($sql) 
     { 
      return new genc_query($sql,&$this); 
     } 
    } 
    class genc_query 
    { 
     private $sql, $conn, $db, $res, $sequences, $num; 
     function __construct($sql_statement,$db) 
     { 
      $sql_statement = trim($sql_statement); 
      if (!empty($sql_statement)) 
      { 
       $this->sql = $sql_statement; 
       $this->conn = &$db; 
       $this->db = &$db->db; 
       $this->analyze(); 
      } 
     } 
     private function analyze() 
     { 
      if ($this->sql !== null) 
      { 
       $this->sequences = genc_db_parser::ParseString($this->sql)->getArray(); 
      } 
     } 
     private function execute() 
     { 
      if ($this->res === null) 
      { 
       $this->res = false; 
       if (isset($this->sequences['select'])) 
       { 
        try 
         { $this->res = $this->db->query($this->sql); } 
        catch (Exception $e) 
         { genc_database::error($e,$this->sql); } 
       } 
       else 
       { 
        try 
         { $this->res = $this->db->exec($this->sql); } 
        catch (Exception $e) 
         { genc_database::error($e,$this->sql); } 
       } 
      } 
      return $this->res; 
     } 
     public function count() 
     { 
      if ($this->num === null) 
      { 
       $req = false; 
       $this->num = false; 
       if (isset($this->sequences['select'])) 
       { 
        $sql = genc_db_parser::ParseString($this->sql)->getCountQuery(); 
        try 
         { $req = $this->db->query($sql); } 
        catch (Exception $e) 
         { genc_database::error($e,$sql); } 
        if ($req) 
         $this->num = $req->fetchColumn(); 
       } 
      } 
      return $this->num; 
     } 
     public function get_result() 
     { 
      if ($this->execute()) 
       return $this->res; 
      return false; 
     } 
     public function get_row() 
     { 
      $this->execute(); 
      if ($this->res && isset($this->sequences['select'])) 
       return $this->res->fetch(PDO::FETCH_ASSOC); 
      return false; 
     } 
     /* Other functions working on the result... */ 
    } 

实施

/* db is the database object */ 
    $db = new genc_database(); 
    /* concurrent connections can be opened. However giving twice the same argument will return the same corresponding opened connection */ 
    $db2 = new genc_database(array('host'=>'localhost','user'=>'myname','pass'=>'mypass','db'=>'mydb'); 
    /* $db->query($sql) will create a query object ($q) attached to this database */ 
    $q = $db->query(sprintf(" 
     SELECT id,name,modified 
     FROM users 
     WHERE id_account = %u", 
     $id 
    )); 
    /* $q->count() will return the number of rows returned by the query (through a COUNT), and without taking the limit into account */ 
    echo $q->count(); 
    /* $q->get_row will return the next row of the current recordset indexed by name */ 
    while ($data = $q->get_row()) 
     echo $data['id'].': '.$data['name'].'<br />'; 
    /* If we do another action than a select, functions ahead will not return an error but false */ 
    /* On other actions, just to execute the query, use get_result(), which will return the number of affected rows */ 
    $p = $db2->query("UPDATE user2 SET modified = NOW() WHERE id = 1"); 
    echo $p->get_result().'<br />'; 

回答

4

随时让我知道它是多么糟糕。

这很糟糕!

...

什么?

好吧,一切的严肃,它没有那么糟糕,因为它是愚蠢。你在包装 PDO在另一类。如果您想为PDO添加更多功能,您应该扩展它。

我的问题是:我怎么才能让我的查询类只能从数据库类中调用?

PDO已经在日常操作中做到这一点。当你prepare查询时,它返回一个PDOStatement对象。您可以将其配置为返回扩展PDOStatement的另一个对象(via PDO::ATTR_STATEMENT_CLASS)。

如果你想用你的解析器来预先处理查询,则需要覆盖execqueryprepare方法在你的类,它扩展PDO。处理完查询后,您可以调用父方法并返回您的扩展语句类。

如果你担心人们调用statement类,而无需通过exec/query/prepare去,只要记住,没有查询可以执行除非语句知道如何访问数据库,并赢得了”没有父PDO对象就能做到这一点。


此外,

$q = $db->query(sprintf(" 
    SELECT id,name,modified 
    FROM users 
    WHERE id_account = %u", 
    $id 
)); 

这简直是荒谬鉴于这种情况。你在这里有一个PDO对象,没有理由不是在这里使用prepared statementsplaceholders。如果你不想一次绑定一个变量(我不怪你),这就是execute's optional array argument的作用。

+1

+1,如果可以的话,我会给+7,以便花时间为一个精心制作的答案。 – markus 2011-04-08 15:53:21

+0

是的,我问,谢谢!我没有想到扩展PDO,我明白为什么现在好多了。关于最后一点,我也必须说你是对的。很久以前的坏习惯... – Nabab 2011-04-08 15:53:34