php数据库类

时间:2011-04-08 14:54:08

标签: php database oop pdo

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

我正在使用三个课程,包括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 个答案:

答案 0 :(得分:4)

  

随时告诉我它有多糟糕。

这很糟糕!

...

什么?

问了

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

  

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

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

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

如果您担心人们在不经过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的用途。