класс базы данных php - PullRequest
       7

класс базы данных php

0 голосов
/ 08 апреля 2011

Я пытаюсь управлять своими подключениями к базе данных и запросами через ООП в 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 />';

1 Ответ

4 голосов
/ 08 апреля 2011

Не стесняйтесь, дайте мне знать, насколько это плохо.

Это плохо!

...

Что?

Ты спросил !

Ладно, со всей серьезностью, это не так плохо, как глупо .Вы оборачиваете PDO в другом классе.Если вы хотите добавить функциональность more в PDO, вы должны вместо этого расширить ее.

Мой вопрос: как я могу сделать мой класс запросов доступным только из базы данных?class?

PDO уже делает это во время повседневных операций.Когда вы prepare запрашиваете, он возвращает PDOStatement объект.Вы можете настроить его так, чтобы он возвращал другой объект ( через PDO::ATTR_STATEMENT_CLASS), который вместо этого расширяет PDOStatement.

Если вы хотите предварительно обработать запрос с помощью вашего анализатора, вам нужно переопределить методы exec, query и prepare в вашем классе, расширяющие PDO.После обработки запроса вы можете вызвать родительский метод и вернуть расширенный класс операторов.

Если вы беспокоитесь о людях, вызывающих класс операторов без выполнения exec / query / prepare, просто имейте в виду, что никакие запросы не могут быть выполнены , если только оператор не знает, как получить доступ к базе данных, и он не сможет сделать это без родительского объекта PDO.


Кроме того,

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

Это совершенно абсурдно, учитывая обстоятельства.Здесь у вас есть объект PDO, нет никакой причины , а не , чтобы использовать подготовленные операторы и заполнители здесь.Если вы не хотите связывать одну переменную за раз (и я вас не виню), для этого нужен необязательный аргумент массива execute .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...