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

StackOverflow https://stackoverflow.com/questions/617646

  •  03-07-2019
  •  | 
  •  

Вопрос

Я создал этот класс для работы с 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;

    }
 }
Это было полезно?

Решение

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

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

  • Поскольку это код PHP5, используйте исключения вместо trigger_error и set_exception_handler при необходимости, пока исключения не станут более распространенными, но это определенно чище и более перспективно.
  • Вы используете синглтон, это не обязательно плохо, но в данном случае, например, одним недостатком будет то, что вы сможете обрабатывать только одно соединение с одной базой данных.
  • Я не знаю, используете ли вы хранимые процедуры, но хранимая процедура может вернуть набор результатов сквозь query() тоже метод.
  • У вас есть две точки с запятой (;;) в конце вашего 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 ...

Цель состоит в том, чтобы сохранить конфигурацию базы данных в файле *.ini (доступном для редактирования непрограммистами).

Я пошел другим путем и создал класс, расширяющий PDO с помощью множества функций-оболочек вокруг него. prepare()/execute(), и это намного лучше, чем встроенные функции (хотя это немного субъективно...).

Еще одна вещь:тебе следует установить PDO::ATTR_EMULATE_PREPARES к false если вы не используете очень старую версию MySQL (<= 4.0).По умолчанию это true, что является огромной головной болью и заставляет вещи непонятным образом ломаться...Думаю, именно поэтому у тебя огромная обертка bindParam() в первую очередь.

Чтобы ответить на ваш вопрос, хороший это код или нет, спросите себя:
Какова добавленная стоимость моего кода по сравнению с прямым использованием PDO?

Если вы найдете хороший ответ, используйте свой код.Если нет, я бы придерживался PDO.

Также попробуйте рассмотреть возможность реализации Zend-фреймворкКласс DB, который работает сам по себе и поддерживает PDO.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top