Pregunta

Creé esta clase para trabajar con PDO, para hacer que las consultas SQL sean "más fáciles" y menos preocupantes.

aquí están mis pensamientos

  • ¿Debería ser más como si la clase DB extendiera PDO?
  • ¿El método de consulta es demasiado grande?¿Debería dividirse en métodos privados llamados...?¿Es esto lo que se conoce como bajo acoplamiento?
  • ¿Mi forma de detectar una consulta SELECT es demasiado fea para su propio bien?
  • ¿Qué otros problemas son evidentes?Como estoy aprendiendo sobre la marcha, estoy seguro de que podría haber pasado por alto muchos problemas potenciales.

Gracias

`

 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;

    }
 }
¿Fue útil?

Solución

No está mal y, como se ha dicho, podría ayudar para aplicaciones pequeñas, aunque en su mayoría es una abstracción muy delgada sobre otra abstracción.No trae muchas otras funcionalidades.

Algo que quizás quieras considerar, entre otras cosas:

  • Como este es el código PHP5, use excepciones en lugar de trigger_error y set_exception_handler si es necesario hasta que las excepciones se generalicen, pero definitivamente es más limpio y está más preparado para el futuro.
  • Está utilizando un singleton, no es necesariamente malo, pero en este caso, por ejemplo, un inconveniente será que solo podrá manejar una conexión a una base de datos.
  • No sé si haces uso de procedimientos almacenados, pero un procedimiento almacenado podría devolver un conjunto de resultados a través de query() método también.
  • Tienes dos puntos y coma (;;) al final de tu new PDO línea.

Dicho esto, no creo que su método de consulta sea demasiado grande y no hay mucho que pueda recuperarse de otros lugares en este momento.Aunque tan pronto como vea dos o tres líneas que podrían llamarse desde otra función, divídalas.Esa es una buena manera de SECO.

Otros consejos

Sí y no

Es un buen código para una aplicación simple, rápida y sucia.

El problema surge cuando se usa esto en una aplicación estructurada más compleja. Donde el manejo de errores variará dependiendo de qué sql esté ejecutando.

También cualquier error grave aparecerá como " problema en la línea 999 " errores de tipo donde 999 está en tu rutina súper duper y tendrás dificultades para rastrearlo a una solicitud sql particular.

Habiendo dicho que hago este tipo de cosas todo el tiempo en proyectos pequeños.

Esto es lo que he usado (solo reemplaza las referencias a Zzz_Config con $ GLOBALS ['db_conf'] o algo así):

/**
 * 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];
    }
}

El uso debería ser:

$db = Zzz_Db::getInstance(); // or Zzz_Db::getInstance('some_named_db')
$stmt = $db->prepare('SELECT ...

El objetivo es mantener la configuración de db en un archivo * .ini (editable por un no codificador).

Fui por el otro lado e hice una clase que extiende PDO con un montón de funciones envolventes alrededor de prepare() / execute(), y es mucho mejor que las funciones integradas (aunque eso es un poco subjetivo ...).

Otra cosa: debe establecer PDO::ATTR_EMULATE_PREPARES en false a menos que esté usando una versión realmente antigua de mysql (< = 4.0). El valor predeterminado es true, que es un gran dolor de cabeza y hace que las cosas se rompan de manera oscura ... lo que supongo que es la razón por la que tienes una gran envoltura alrededor de bindParam() en primer lugar.

Para responder a su pregunta, si es un buen código o no, pregúntese:
¿Cuál es el valor agregado de mi código en comparación con el uso de PDO directamente?

Si encuentra una buena respuesta, use su código. Si no, me quedaría con PDO.

También intente considerar la implementación de la clase DB de Zend Framework que funciona por sí solo y es compatible con PDO.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top