Intereting Posts
Codeigniter с использованием базы данных доступа ms Как конвертировать MM / DD / YYYY в YYYY-MM-DD? Есть ли способ перенаправить на другую страницу в php без использования header ()? Данные сеанса PHP не сохраняются «Карта для существующих таблиц» в построителе расширений, показывающая странные проблемы в TYPO3 как получить запись «0» в объекте Doctrine 2 DQL – как выбрать обратную сторону однонаправленного запроса «многие ко многим»? Добавление резервного изображения в цикл специальных настраиваемых полей wordpress Как создать всплывающее окно (модальное диалоговое окно) в HTML Сгенерировать изображения с помощью ImageMagick без сохранения в файл, но все же отображать их на веб-сайте Внедрение пространств имен в режиме без жира Как вызвать скрипт PHP с использованием AJAX внутри функции переключения JQuery? preg_replace, чтобы изменить URL-адрес относительно абсолютного Как проверить, существует ли элемент массива? Что лучше: mysql_connect или mysql_pconnect

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

Я пытаюсь управлять своими подключениями к базе данных и запросами через ООП в PHP, и я не очень хорош в этом. Я знаю, что я изобретаю колесо, но так мне нравится 🙂

Я использую три класса, включая синтаксический анализатор SQL, который я сам не сделал. Моя реализация возвращает объект при создании нового соединения. Этот объект базы данных должен создать новый экземпляр запроса (один экземпляр для оператора SQL). Мой вопрос: как я могу заставить свой класс запроса быть только invocable из класса базы данных?

Я вставляю резюме моих классов и реализацию ниже. Не стесняйтесь, дайте мне знать, насколько это плохо. Благодаря!

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

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

Это плохо!

Какие?

Вы спросили !

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

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

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 .