O mundo orientado a objetos

Classe de conexão com php utilizando PDO

22 de Agosto de 2010

Olá neste artigo vamos aprender a fazer conexão com um banco de dados utilizando um recurso muito bacana que o php nos oferece, o PDO (PHP Data Object). Ele é um objeto que possibilita tornar sua "fábrica de conexões" - já vou exeplicar também - portável.

Imagine que você está usando o banco de dados MySql e que a vida é bela e seu sistema sempre usará este banco! lindo esse sonho não? :)

Tá! agora acorda! e veja como o mundo é cruel e as coisas não tão simples assim. Pois se você se baseia totalmente em usar funções como mysqli_connect() , mysqli_.. qualquer coisa., trate de terminar de ler este artigo!

E se esta galera! Estes métodos estão misturados em diversas partes do seu código! Vai te dar uma dor de cabeça sem tamanho, só de pensar em mudar de banco de dados. Pensando nessa, foi que desenvolveram um recurso no php, o PDO. Uma classe que se encarrega de fazer o gerenciamento dos drivers pra você. Isso mesmo! parece que existe uma luz no fim do túnel!

E lembra do que falei? - "fábrica de conexões"

Este é outro conceito muito usado, para garantir tanto uma certa organização quanto a integridade do banco de dados. É o pattern conhecido como Singleton.

Qual é a idéia? Manter uma instância única para que toda a aplicação possa utilizá-la. Veja como isso faz sentido ser utilizado principalmente para conectar-se com um banco. Toda vez que se conecta o banco abre uma porta, e se você criar conexões sem nenhum controle, dependendo do número de acessos que o seu site tiver ele vai derrubar o banco.

O conceito deste pattern está bem explícito na própria wikipedia, mas vamos fazer um código aqui também. Então vamos ao que intereça:

O PDO


/*
 Chega de funções, e funções. Tudo no método construtor do PDO
*/
$pdo = new PDO("tipoDeBanco:host=EnderecoDoHost;dbname=nomeDoBanco", "usuário", "senha" );

Veja só, o objeto já faz tudo numa tacada só. Depois disso é só ir trabalhando com ele e seus métodos de interface.

Executando uma query

Se estiver executando local, o host é localhost, senha não tem e usuário é root. Há e o tipo de banco de dados também!

<?php
try {
	// PDO em ação!
	$pdo = new PDO ( "mysql:host=localhost;dbname=tutorial", "root", "" );

	// Com o objeto PDO instanciado
	// preparo uma query a ser executada
	$stmt = $pdo->prepare("SELECT * FROM cliente");

	// Executa query
	$stmt->execute();

	// lembra do mysql_fetch_array?
	//PDO:: FETCH_OBJ: retorna um objeto anônimo com nomes de propriedades que
	//correspondem aos nomes das colunas retornadas no seu conjunto de resultados
	//Ou seja o objeto "anônimo" possui os atributos resultantes de sua query
	while ( $obj = $stmt->fetch ( PDO::FETCH_OBJ ) ) {

		// Resultados podem ser recuperados atraves de seus atributos
		echo "<b>Nome:</b> " . $obj->nome . " - <b>Telefone:</b> " . $obj->fone."</br>";
	}
	// fecho o banco
	$pdo = null;
	// tratamento da exeção
} catch ( PDOException $e ) {
	echo $e->getMessage ();
}
?>

obs: com a função fetch() é possível trazer os resultados de várias maneiras, este foi só um exemplo. O que determina o tipo de retorno é a constante "PDO::FETCH_OBJ", para mais informações vide manual. Sobre a função fetch().

Compare! um exemplo com o modo tradicional de conexão com MySql

Veja que está tudo dentro de um bloco try, catch. Para quem não sabe, o programa quando encontra um erro dentro de um bloco try, salta para o catch e consegue recuperar a exceção ou erro, por um objeto de exceção que vem por parâmetro. Para mais informações sobre o uso de pdo visite seu manual no site oficial do php.

A fabrica de conexões

Se você seguiu o link que existe ali em cima, já deve ter visto a página da wikipedia com exemplos em diversas linguagens do pattern Singleton, mas vamos terminar a coisa aqui pra não ficar dúvida! :)


<?php
class Conexao extends PDO {

	private static $instancia;

	public function Conexao($dsn, $username = "", $password = "") {
		// O construtro abaixo é o do PDO
		parent::__construct($dsn, $username, $password);
	}

	public static function getInstance() {
		// Se o a instancia não existe eu faço uma
		if(!isset( self::$instancia )){
			try {
				self::$instancia = new Conexao("mysql:host=localhost;dbname=conteudo", "root", "");
			} catch ( Exception $e ) {
				echo 'Erro ao conectar';
				exit ();
			}
		}
		// Se já existe instancia na memória eu retorno ela
		return self::$instancia;
	}
}
?>

Então fazendo uso desta classe toda vez que eu quiser fazer conexão com o banco eu uso o método implementado getInstance(), pois ele é quem vai me retornar uma conexão existente ou criá-la para mim.

Veja que eu coloquei direto alí os valores, senhas e talls.. pra conectar certo. Então, porém tanto pra php quanto pra java - falando de web - o ideal é centralizar todas as configurações em um único arquivo, para o site. Em java se faz uso do arquivo de configuração web.xml, já no php este arquivo de configuração geral é mais conhecido como config.

É nada mais nada menos que um arquivo com extensão .php que contem todas as configurações necessárias para o site. Acho que esse assunto ainda rende um post, vou colocar algo a respeito futuramente!
é isso obrigado por ler este post, e até a próxima! vlew :)

:: Este post possui uma complementação neste outro artigo! Usando Classe de Conexão com PDO (exemplos práticos)

avatar

Sobre Rodrigo Ireno

Sem descrição. Por favor, complete seu perfil.
Comentários (33) Trackbacks (3)
  1. A Fabrica de conexões ficou muito boa, mas não consigo implementa-la, criei um arquivo com o código acima chamado conexao.class.php e um arquivo chamado teste.php onde dei o include(“conexao.class.php”), agora preciso instanciar a classe, vc poderia colocar um exemplo de como faço isso…tentei $conn = new Conexao(); mas deu erro.
    • Então Bruno, neste caso você não irá utilizar new. Dê include e utilize a seguinte chamada “Conexao::getInstance()” – ele irá retornar o objeto PDO para você.
      Se você reparar este método é estático – (usei a declaração static na assinatura do método), então ele pode ser chamado desta forma, sem se quer instanciar o objeto.
  2. Rodrigo, apenas mais uma dúvida, caso eu defina constantes em um arquivo config.php ex: define(“DB_HOST”), que alteração eu deveria fazer na classe para que ela funcione.

    Desculpe a ignorancia, já programei bastante tempo em php mas não O.O.

    • Então, constantes no config funcionam normalmente, só declarar com define() no config. e utilizar autoload para carregar as classes. A gente tem um artigo sobre autoload, acho que foi o meu último. Dê uma olhada, tente implementar.

      geralmente os programadores utilizam, pra DB_HOST, DB_USER, DB_PASS. Daí não tem segredo! é concatenação de string. lá no construtor da sua fabrica de conexões, concatene DB_HOST no lugar de “localhost” e assim sucessivamente para os outros parâmetros.

      mais pra frente vou colocar mais alguns artigos sobre pdo, daí eu deixo uma estrururinha bem legal. tenta lá..

  3. Consegui…rs
  4. veja esse, também se aplica para carregar a classe de conexão:

    http://objota.com.br/web/php/utilizando-config-para-carregar-suas-classes.html

  5. Cara, esse código de conexão me salvou! Muito obrigado.
  6. Salve galera,

    Aproveitando o tema sobre a extensão PDO, venho aqui recomendar o uso da classe PDO4You, a qual estou utilizando a um bom tempo atrás e tem se tornado a base dos meus projetos.

    Para quem se interessar, possui um repositório no github para poder baixar e utilizar em suas aplicações, ou simplesmente acompanhar e/ou compartilhar.

    Segue link: https://bitly.com/PDO4You

    Envie suas sugestões ou críticas, e ajudem a tornar esta classe ainda melhor para benefício de todos e assim seja até quando o PHP existir. =D

    Abraços.

  7. Classe PDO4You = PDO + Singleton + CRUD + JSON

    http://bitly.com/PDO4You

  8. ficaria melhor se fizesse assim :

    dbh = new PDO(self::$dsn,self::$user,self::$pass);
    } catch (PDOException $e) {
    echo ‘Connection failed: ‘ . $e->getMessage();
    }
    }
    public static function getInstance(){
    if(!isset(self::$instance)){
    $object= __CLASS__;
    self::$instance=new $object;
    }
    return self::$instance;
    }

    }

    e pra implementar assim :

    $sql = “select login, email from users where id = :id”;

    try {
    $core = Core::getInstance();
    $stmt = $core->dbh->prepare($sql);
    $stmt->bindParam(‘:id’, $this->id, PDO::PARAM_INT);

    if ($stmt->execute()) {
    $o = $stmt->fetch(PDO::FETCH_OBJ);

    // blablabla….

  9. Porque você declarou a propriedade $instancia como static?
    • teóricamente pelo que eu vejo em java, uma instancia declarada como static fica na memória do computador até a aplicação terminar. Isso é só pra ter certeza de que ela não será “detruida” por falta de uso, estando assim sempre disponível para qualquer um que queira usá-la.
  10. Mas no caso, não vejo utilidade, já que ao final da execução do código a conexão é encerrada! Outra coisa, ao invés de ter uma classe chamada conexão, não é melhor ter uma classe chamada BD que seja responsável por toda a interação com o Banco de Dados? Isso evita código repetido!
    • A idéia da classe conexao é somente prover uma instancia de conexao com o banco, se vc prefere mudar algumas coisas fique a vontade. Um outro conceito que seria interessante vc procurar é o da camada DAO. tem um site “revista php” (põe no google ), se não me engano, que tem uma matéria mais completa de DAO. Procure dar uma olhada.
    • Pesquise um pouco a respeito de MVC e verá que a idéia não é centralizar a coisa toda em um lugar, e sim organizar de maneira que seja possível entender e documentar (tudo de maneira lógica). Isso não significa que seja sempre a melhor opção, alguns padrões carregam consigo alguma redundância, por vezes irritante, porém necessária.
  11. Parabéns pela matéria, sou inciante no PHP e estou implementando um PDO+SINGLETON+DAO e está sendo de grande ajuda!
    • Eu gostaria inclusive de uma opinião sobre isso, nesse caso se tornam tantas camadas e etc que não sei se é realmente necessário mas, acho que o PDO é auto justificável, coloquei o singleton pois considero uma boa pratica de programação principalmente em um projeto que resultará é um grande volume de requisições ao banco de dados e utilizei o DAO por ser uma pratica muito difundida e ter a vantagem de centralizar a iteração com o banco. No caso desse sistema fiz com que uma classe “DAO” seja a unica a manipular a conexão com o banco de dados (o simgleton). Acredito que existam algumas vantagens nesse “modelo” mas também acrescenta certa complexidade ao projeto…
      Fico aberto a sugestões e opiniões!
      Grande abraço.
      • Quando se trabalha em equipe com programadores, analistas e gerente de projeto, tudo isso é necessário para documentar e organizar não somente o sistema, mas também o fluxo de trabalho dos colaboradores.

        Eu mesmo vejo que graças ao java, existem muitos padrões porque a arquitetura da linguagem não proporciona algum recurso. Por tanto nem sempre faz sentido fazer tudo dentro dos padrões ( Padrão é uma ganbiarra que todo mundo faz; quando todo mundo faz, é certo ).

        Hoje a idéia é, tenho um objeto no meu modelo de negócio:
        usuário** então

        Usuario.class.php com todos os atributos do usuário ( esse cara será o “value object”)

        UsuarioDAO.class.php esse cara interage com o banco de dados ( obtém uma conexão através da classe singleton )

        veja que singleton não faz parte do negócio, mas é necessário para a solução, isso é muito bem tratado no paradigma de “Programacão Orientada a Aspectos”

        Bom viagei, keep calm. qualquer coisa posta aí

        • Realmente, em equipes grandes ou distribuídas é muito importante usar essas técnicas. Estou desenvolvendo o sistema sozinho mas mesmo assim vejo a necessidade. Estou implementando muito parecido com o que você descreveu. Até agora não tenho tido problemas além da complexidade na implementação mas, sei que isso me ajudará bastante na manutenção!

          Recomendo muito o uso do PDO, assim como também do Singleton e DAO. Agradeço mais uma vez pela matéria e espero ver outras.

          Um assunto que ainda me é obscuro e tenho interesse de conhecer é sobre cookies, dizem que auxilia bastante na segurança entre outros. Fica a dica e o pedido!

  12. Assim como o Bruno Loiola, tive uma dúvida sobre a utlização da classes em outras páginas em php.

    Tenho que inserir em todas as páginas o include e a chamada: $db = conexao::getInstance();. Ou não precisa.

    • Não precisamos fazer include o tempo todo, podemos incluir ele na fila de includes do __autoload(). Aqui neste blog tem um artigo a respeito disso.
      E o conexao::getInstance() é uma instancia que possui conexao com o banco de dados, chame este comando somente onde for fazer manipulação de dados. Mas antes meu conselho é ler a respeito de spl_autoload_register(), aqui no blog mesmo.
      []‘s
  13. Como eu chamo ou instancio esta classe Conexao em outra página ou bloco de código??? Tenho que criar uma objeto da classe Conexao e chamar ou posso chamar direto para uma variável visto que o metodo e static????
    • Aqui é uma boa hora para utilizar spl_autoload_register, colocando essa classe de conexão na sua lista de classes a carregar.

      Após isso é só passar o objeto para uma variável a passar a utilizá-lo.

  14. cara fui utilizar esta classe e funcionou beleza, mas no momento q fui implementar um login e utilizar esta função do PDO:

    “$stmt->bind_param(1, $login, PDO::PARAM_STR);”

    me retornou este erro:

    “Call to undefined method PDOStatement::bind_param()”

    Sabe me dizer o pq?
    Eu fiquei pensando e ñ entendi.

  15. Parabens pelo artigo, esta me ajudando muito , ja que ainda sou aprendiz en não manjo quase nada de POO, apenas estruturado mesmo e estou engatinhando com o POO
  16. Essa é um modelo que criei, como reutilizo a messa class para diversos projetos deixo as variáveis fora da função. caso alguém ache mais simples. copie.

    Obs: existe um armazenamento do erro em cookie por que tenho uma função de debug em meus sistema que eu ativo e desativo quando quero, pois posso exibir o erro em qualquer página que minhas classes ou funções fez o uso do banco de dados. Exite também uma correção de caracteres para o formato ‘UFT-8′, exibindo todos os caracteres corretamente.

    class PDOclass {
    protected $pdo;
    // Infos to Database
    private $HOST = ’0.0.0.0′;
    private $DBNAME = ‘nome_do_banco’;
    private $USER = ‘usuário_do_banco’;
    private $PASS = ‘senha_do_usuário’;

    function __construct(){
    try {
    $dns = “mysql:host=”.$this->HOST.”;dbname=”.$this->DBNAME;
    $pdo = new PDO($dns,$this->USER,$this->PASS);
    $pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
    $pdo->exec(“SET NAMES utf8″);
    setcookie(“ErroPDO”,”",time()-3600);
    $this->pdo = $pdo;
    }catch(PDOException $e){
    setcookie(“ErroPDO”,”Falha ao conectar ao banco de dados – “.$e->getMessage());
    }
    }
    //$pdo = $this->pdo; // use essa instância para fazer uso da conexão.

    /* exemplo rápido de como criar uma função usando a propria class de conexão…

    function nome_funcao(){
    $pdo = $this->pdo;
    try {
    $stmte = $pdo->prepare(“SELECT * …..”);
    // Os comandos….
    }catch(PDOException $e){
    // caso de erro…
    }
    }
    */

    }

    // uma forma de usar em outra class…
    /*
    class uma_class_qualquer extends PDOclass {
    function nome_funcao(){
    $pdo = $this->pdo;
    try {
    $stmte = $pdo->prepare(“SELECT * …..”);
    // Os comandos….
    }catch(PDOException $e){
    // caso de erro…
    }
    }
    }
    */

  17. Olá amigos
    estou começando a usar o PDO, estou tentando
    selecionar outro banco de dados depois da conexão estabelecida
    com mysql simples se usa “mysql_select_db()” mas no pdo não sei como fazer isso
    se alguém puder me ajudar agradeço
  18. boa tarde, estou tentando usar esta classe no lugar da mysqli.. porem estou tendo um problema. uso algumas variaveis dentro do servidor mysql. “que se eu desconectar sao apagadas”. elas sao atribuidas quando faço o login. porem toda vez que eu chamo esta classe de um php novo. as variaveis do mysql foram perdidas. já coloquei o atributo persistent no contruto, “que pelo que eu entendi. deixaria sempre a mesma conexao. porem nao consegui fazer funcionar. a cada vez que chamo a classe uma nova conexao é criada e minhas variaveis sao destruidas. alguma dica?

    obrigado


Deixar um comentário