Я пытаюсь управлять своими подключениями к базе данных и запросами через ООП в PHP, и у меня это плохо получается.Я знаю, что заново изобретаю колесо, но мне так нравится :)
Я использую три класса, в том числе парсер SQL Я сам этого не сделал.Моя реализация возвращает объект при создании нового соединения.Программист должен создать новый экземпляр запроса (один экземпляр на оператор 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 />';