Я построил этот класс для работы с PDO, чтобы упростить SQL-запросы и не беспокоиться.
Вот мои мысли
спасибо
`
class Db { private static $_instance = NULL; private function __construct() { // can not call me } private function __clone() { // no! } public static function getInstance() { if (!self::$_instance) { try { self::$_instance = new PDO('mysql:host=' . CONFIG_MYSQL_SERVER . ';dbname=' . CONFIG_MYSQL_DATABASE, CONFIG_MYSQL_USERNAME, CONFIG_MYSQL_PASSWORD);; self::$_instance-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e) { trigger_error($e->getMessage()); } } return self::$_instance; } public static function query($query /*string*/, $bindings = NULL) { $queryPortion = substr($query,0, 6); try { if ($bindings) { $prepared = self::getInstance()->prepare($query); foreach($bindings as $binding=>$data) { // defaults to string if (!is_array($data)) { $prepared->bindParam($binding, $data); } else { switch(count($data)) { case 1: $prepared->bindParam($binding, $data['value']); break; case 2: $prepared->bindParam($binding, $data['value'], $data['dataType']); break; case 3: $prepared->bindParam($binding, $data['value'], $data['dataType'], (int)$data['length']); break; default: trigger_error('An error has occured with the prepared statement bindings.'); return false; break; } } } $prepared->execute(); return $prepared->fetchAll(PDO::FETCH_ASSOC); } else if (String::match($queryPortion, 'select')) { // if this is a select query $rows = self::getInstance()->query($query); return $rows->fetchAll(PDO::FETCH_ASSOC); } else { return self::getInstance()->exec($query); } } catch(PDOException $e) { trigger_error($e->getMessage()); } } public static function getLastInsertId() { try { self::getInstance()->lastInsertId(); } catch(PDOException $e) { trigger_error($e->getMessage()); } } public static function disconnect() { // kill PDO object self::$_instance = NULL; } }
Это неплохо, и, как было сказано, это может помочь небольшим приложениям, хотя это в основном очень тонкая абстракция на другой абстракции. Это не приносит много других функций.
Что-то, что вы, возможно, захотите рассмотреть, среди прочего:
trigger_error
и set_exception_handler
если необходимо, до тех пор, пока исключения не станут более распространенными, но это определенно чище и set_exception_handler
. query()
. ;;
) в конце вашей new PDO
линии new PDO
. При этом я не думаю, что ваш метод запросов слишком велик, и на данный момент не так много можно вспомнить из других мест. Хотя, как только вы увидите две или три строки, которые могут быть вызваны из другой функции, разделите ее. Это хороший способ СУХОЙ .
Да и нет.
Это хороший код для простого быстрого и грязного приложения.
Проблема возникает, когда вы используете это в более сложном структурированном приложении. Если обработка ошибок будет различаться в зависимости от того, какой sql вы выполняете.
Кроме того, любые серьезные ошибки будут отображаться как ошибки типа «проблема при строке 999», где 999 находится в вашей процедуре супер-пупер, и вам будет сложно найти ее обратно к конкретному запросу sql.
Сказав, что я все это время делаю на небольших проектах.
Вот что я использовал (просто замените ссылки на Zzz_Config на $ GLOBALS ['db_conf'] или что-то в этом роде:
/** * Extended PDO with databse connection (instance) storage by name. */ class Zzz_Db extends PDO { /** * Named connection instances. * * @var array */ static private $_instances; /** * Retrieves (or instantiates) a connection by name. * * @param string $name Connection name (config item key). * @return Zzz_Db Named connection. */ static public function getInstance($name = null) { $name = $name === null ? 'db' : "db.$name"; if (!isset(self::$_instances[$name])) { if (!$config = Zzz_Config::get($name)) { throw new RuntimeException("No such database config item: $name"); } if (!isset($config['dsn'])) { if (!isset($config['database'])) { throw new RuntimeException('Invalid db config'); } $config['dsn'] = sprintf('%s:host=%s;dbname=%s', isset($config['adapter']) ? $config['adapter'] : 'mysql', isset($config['host']) ? $config['host'] : 'localhost', $config['database']); } $db = self::$_instances[$name] = new self( $config['dsn'], isset($config['username']) ? $config['username'] : null, isset($config['password']) ? $config['password'] : null); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, 'Zzz_Db_Statement'); if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') { $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $db->exec('SET CHARACTER SET utf8'); } } return self::$_instances[$name]; } }
Использование:
$db = Zzz_Db::getInstance(); // or Zzz_Db::getInstance('some_named_db') $stmt = $db->prepare('SELECT ...
Цель состоит в том, чтобы сохранить конфигурацию db в файле * .ini (редактируется некодером).
Я пошел в другую сторону и создал класс, который расширяет PDO с помощью множества функций-оболочек вокруг prepare()
/ execute()
, и это намного лучше, чем встроенные функции (хотя это немного субъективно …).
Еще одна вещь: вы должны установить для PDO::ATTR_EMULATE_PREPARES
значение false
если вы не используете действительно старую версию mysql (<= 4.0). Он по умолчанию имеет значение true
, что является огромной головной болью и заставляет вещи ломаться в неясных способах …, которые, как я предполагаю, является причиной того, что у вас есть огромная оболочка вокруг bindParam()
.
Чтобы ответить на ваш вопрос, если это хороший код или нет, спросите себя:
Какова добавленная стоимость моего кода по сравнению с использованием PDO напрямую?
Если вы найдете хороший ответ, пойдите для использования своего кода. Если нет, я буду придерживаться PDO.
Также попробуйте рассмотреть возможность реализации класса DB Zend Framework, который работает сам по себе и поддерживает PDO.