Pergunta

Eu construí esta classe para trabalhar com DOP, para fazer consultas SQL 'mais fácil' e menos para se preocupar.

Aqui estão os meus pensamentos

  • Deve ser mais como classe DB estende DOP?
  • É o método de consulta muito grande? Deve ser dividido em métodos privados que são chamados .. é isso que é conhecido como acoplamento ?
  • é o meu caminho para a detecção de uma consulta SELECT feio demais para seu próprio bem?
  • O que outros problemas são evidentes? Como eu sou tipo de ensino-como-eu-go, tenho certeza de que eu poderia ter esquecido um monte de problemas potenciais.

Obrigado

`

 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;

    }
 }
Foi útil?

Solução

Não é ruim e como tem sido dito que poderia ajudar para pequenas aplicações, embora seja principalmente uma abstração muito fina em outra abstração. Não está trazendo um monte de outras funcionalidades.

Algo que você pode querer considerar, entre outras coisas:

  • Como este é o código PHP5, utilize exceções vez de trigger_error e set_exception_handler se necessário, até exceções são mais difundida, mas é definitivamente mais limpo e mais à prova de futuro.
  • Você está usando um singleton, não é uma coisa ruim, necessariamente, mas, neste caso, por exemplo, uma falha será que você só vai ser capaz de lidar com uma conexão a um banco de dados.
  • Não sei se você fizer uso de procedimentos armazenados, mas um procedimento armazenado pode retornar um conjunto de resultados através do método query() também.
  • Você tem dois pontos e vírgulas (;;) no final da sua linha new PDO.

Dito isto, eu não acho que o seu método de consulta é muito grande e não há muito que possa ser lembrado de outro lugar lá no momento. Apesar de, logo que você ver duas ou três linhas que poderiam ser chamados a partir de outra função, dividi-lo. Essa é uma boa maneira de DRY .

Outras dicas

Sim e Não.

É bom código para uma rápida simples e aplicação sujo.

O problema surge quando você usar isso em uma aplicação estruturada mais complexa. Onde a manipulação de erro irá variar dependendo de qual o SQL você está executando.

Além disso, quaisquer erros graves vai aparecer como "problema na linha 999" erros de tipo onde 999 é o seu super duper rotina e você vai ter dificuldade em rastreá-lo de volta a um pedido sql particular.

Tendo dito que eu faço esse tipo de coisa me o tempo todo em pequenos projectos.

Aqui está o que eu usei (apenas substituir as referências ao Zzz_Config com US $ GLOBALS [ 'db_conf'] ou algo assim):

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

Uso whould ser:

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

O objetivo é manter a configuração db em um arquivo .ini * (editável por um não-codificador).

Eu fui para o outro lado e fez uma classe que estende DOP com um monte de funções invólucro em torno prepare() / execute(), e é muito mais agradável do que o construído em funções (apesar de que é um pouco subjetivo ...).

Uma outra coisa: você deve definir PDO::ATTR_EMULATE_PREPARES para false a menos que você estiver usando uma versão muito antiga do MySQL (<= 4,0). O padrão é true, que é uma enorme dor de cabeça e faz as coisas quebram de maneiras obscuras ... o que eu estou supondo que é a razão que você tem uma enorme invólucro em torno bindParam() em primeiro lugar.

Para responder à sua pergunta, se ele é um código bom ou não, pergunte-se:
Qual é o valor acrescentado do meu código em relação ao uso DOP diretamente?

Se você encontrar uma resposta boa, ir para usando seu código. Se não, eu iria ficar com DOP.

Além disso, tente considerando implementar Zend Framework 's DB classe que trabalha por conta própria e suportes PDO.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top