php数据库类 [英] php database class

查看:56
本文介绍了php数据库类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to manage my database connections and queries through OOP in PHP, and I'm not great at it. I know I'm reinventing the wheel, but that's the way I like it :)

我正在使用三个类,包括 SQL解析器做我自己.创建新连接时,我的实现返回一个对象.程序员应通过该数据库对象创建一个新的查询实例(每个SQL语句一个实例).我的问题是:如何使查询类只能从数据库类中调用?

I am using three classes, including a SQL parser I haven't done myself. My implementation returns an object when a new connection is created. Programmer should create a new query instance (one instance per SQL statement) through this database object. My question is: how can I get my query class to be only invocable from the database class?

我要粘贴我的课程和下面的实现的简历.随时让我知道它有多糟.谢谢!

I'm pasting a resume of my classes and the implementation below. Feel free to let me know how bad it is. Thanks!

    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 />';

推荐答案

随时让我知道它有多糟糕.

Feel free to let me know how bad it is.

不好!

...

什么?

询问

好吧,总的来说,它并没有愚蠢那么糟.您正在包装另一个类中的PDO.如果要向PDO添加 more 功能,则应该扩展它.

Okay, in all seriousness, it's not so much bad as it is silly. You're wrapping PDO in another class. If you want to add more functionality to PDO, you should be extending it instead.

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

My question is: how can I get my query class to be only invocable from the database class?

PDO已在日常操作中执行此操作.当您 prepare 查询时,它将返回 PDOStatement 对象.您可以将其配置为通过PDO::ATTR_STATEMENT_CLASS 返回另一个对象()而是扩展PDOStatement.

PDO already does this during day to day operations. When you prepare a query, it returns a PDOStatement object. You can configure it to return another object (via PDO::ATTR_STATEMENT_CLASS) that extends PDOStatement instead.

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

If you want to pre-process the query using your parser, you'll need to override the exec, query and prepare methods in your class that extends PDO. Once you've processed the query, you can call the parent method and return your extended statement class.

如果您担心有人在不通过exec/query/prepare的情况下调用语句类,请记住,除非语句知道,否则无法执行任何查询如何访问数据库,如果没有父PDO对象,它将无法做到这一点.

If you're worried about people invoking the statement class without going through exec/query/prepare, just keep in mind that no queries can be executed unless the statement knows how to access the database, and it won't be able to do that without the parent PDO object.

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

在这种情况下,这是完全荒谬的.您在这里有一个PDO对象,没有理由使用准备好的声明占位符.如果您不想一次绑定一个变量(我也不怪您),那就是 execute的可选数组参数用于.

This is downright absurd given the circumstances. You have a PDO object here, there's no reason not to use prepared statements and placeholders here. If you don't want to bind one variable at a time (and I don't blame you), that's what execute's optional array argument is for.

这篇关于php数据库类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆