我想通过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 />';
+1,如果可以的话,我会给+7,以便花时间为一个精心制作的答案。 – markus 2011-04-08 15:53:21
是的,我问,谢谢!我没有想到扩展PDO,我明白为什么现在好多了。关于最后一点,我也必须说你是对的。很久以前的坏习惯... – Nabab 2011-04-08 15:53:34