Является ли эта оболочка для PDO «хорошим кодом»? Существуют ли какие-либо потенциальные проблемы?

Я построил этот класс для работы с PDO, чтобы упростить SQL-запросы и не беспокоиться.

Вот мои мысли

  • Должна ли она быть более похожей на класс DB расширяет PDO?
  • Является ли метод запроса слишком большим? Если он будет разделен на частные методы, которые называются … это то, что известно как свободная связь ?
  • Является ли мой способ обнаружения запроса SELECT слишком уродливым, потому что это хорошо?
  • Какие еще проблемы очевидны? Поскольку я своего рода обучение, как-я-го, я уверен, что мог бы упустить много потенциальных проблем.

спасибо

`

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; } } 

Solutions Collecting From Web of "Является ли эта оболочка для PDO «хорошим кодом»? Существуют ли какие-либо потенциальные проблемы?"

Это неплохо, и, как было сказано, это может помочь небольшим приложениям, хотя это в основном очень тонкая абстракция на другой абстракции. Это не приносит много других функций.

Что-то, что вы, возможно, захотите рассмотреть, среди прочего:

  • Поскольку это код PHP5, используйте исключения вместо 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.