Você está na página 1de 11

Captulo 6

PHP Data Objects (PDO)


6.1 O que o PDO?
Muitas aplicaes ainda utilizam a extenso clssica do MySQL, ou ento as extenses nativas de PostgreSQL e SQLite, para comunicao com estes bancos. No s
as aplicaes cam atreladas a um banco especco, mas a manuteno se torna
difcil e, imagine ento, se for necessria uma migrao de um banco de dados para
outro, por exemplo do MySQL para PostgreSQL? O PDO uma soluo inteligente
para esse problema bastante complexo. O PDO uma camada de abstrao de
acesso a dados, que signica que, independente do banco de dados que voc est
utilizando, poder usar as mesmas funes para executar queries e consultar dados.
Vamos ver, na prtica, exemplos de como usar o PDO, como ele torna seu cdigo
mais fcil de manter, e porque importante no atrelar sua aplicao a um banco
de dados especco. O PDO, PHP Data Objects, foi introduzido no PHP 5.1 e d
suporte a vrias sistemas gerenciadores de banco de dados, como MySQL, PostgreSQL, SQLite, Informix, Oracle, SQL Server, IBM, entre outros. Alm disso, ele
torna fcil a criao de prepared statements e transactions nestes sistemas, se precisar atrelar seu sistema a funcionalidades especcas de cada extenso de cada
banco de dados.

63

6.2 Conexo

4Linux www.4linux.com.br

6.2 Conexo
A conexo com um banco de dados atravs do PDO se d durante a instanciao do
objeto da classe PDO, passando as informaes de conexo com o banco na forma
de uma DSN, ou data source name, alm das credenciais de acesso. Portanto, o
mtodo construtor da classe PDO espera trs parmetros:

<? php

2
3

// MySQL

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

5
6

// PostgreSQL

$db = new PDO (" pgsql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

8
9
10

// SQLite
$db = new PDO (" sqlite : meubanco . sqlite ");

Uma vez que o objeto da classe PDO tenha sido instanciado, estamos conectados
com nosso banco. Para desconectarmos, podemos matar o objeto ou aguardar que
ele seja morto automaticamente ao nal do script.

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

4
5

unset ( $db );

Pgina 64

Desenvolvimento Orientado a Objetos com PHP

4Linux www.4linux.com.br

6.3 Executando comandos

6.3 Executando comandos


Depois de conectar com o banco de dados instanciando um objeto da classe PDO,
podemos chamar alguns mtodos desse objeto para executarmos comandos em
nosso sistema gerenciador de banco de dados usando a linguagem SQL. Para executar estes comandos, vamos fazer uso do mtodo exec.

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

$db -> exec (" CREATE TABLE posts ( id INT AUTO_INCREMENT , titulo VARCHAR
(255) , conteudo TEXT )");

Atravs do mtodo exec podemos manipular nosso banco de dados da maneira que
quisermos utilizando SQL. Este mtodo sempre retornar o nmero de linhas afetadas pelos nossos comandos. Observe que, caso nenhuma linha seja afetada, o
mtodo retornar zero.

6.4 Fazendo consultas


Podemos utilizar o mtodo exec para executar qualquer comando SQL em nosso
banco, mas quando quisermos fazer consultas, precisamos utilizar outro mtodo. O
mtodo query executa um comando SQL e retorna um objeto da classe PDOStatement contendo os resultados da consulta feita. Objetos da classe PDOStatement
podem ser iterados, j que so uma coleo de dados retornados pela nossa consulta.

<? php

Desenvolvimento Orientado a Objetos com PHP

Pgina 65

6.4 Fazendo consultas


3

4Linux www.4linux.com.br

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

$dados = $db -> query (" SELECT * FROM posts ");

Agora que j temos nossa consulta feita, precisamos acessar os dados retornados
por ela de alguma forma, certo? Os mtodos fetch e fetchAll servem para isso. O
mtodo fetch ir retornar apenas um resultado de nossa consulta, enquanto o mtodo
fetchAll ir retornar todos os resultados. Estes mtodos podem retornar um array ou
um objeto, dependendo dos parmetros passados.

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

$dados = $db -> query (" SELECT * FROM posts ");

$todos = $dados -> fetchAll () ;

$um = $dados -> fetch () ;

7
8

print_r ( $todos );

print_r ( $um );

Observe que, por padro, os mtodos fetch e fetchAll retornam ndices associativos
(com os nomes de nossas colunas) e numricos (dando uma posio para cada
coluna de acordo com a ordem original). Podemos fazer com que somente ndices
associativos sejam trazidos, ou apenas numricos:

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

$dados = $db -> query (" SELECT * FROM posts ");

$associativo = $dados -> fetchAll ( PDO :: FETCH_ASSOC );

$numerico = $dados - > fetchAll ( PDO :: FETCH_NUM );

Pgina 66

Desenvolvimento Orientado a Objetos com PHP

4Linux www.4linux.com.br
8

print_r ( $associativo );

print_r ( $numerico );

6.5 Transactions

Podemos congurar os mtodos fetch e fetchAll para, ao invs de retornarem um


array, retornarem um objeto annimo onde as propriedades so nossas colunas:

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

$dados = $db -> query (" SELECT * FROM posts ");

$obj = $dados -> fetchAll ( PDO :: FETCH_OBJ );

6
7

echo $obj -> titulo ;

6.5 Transactions
Transactions, ou transaes, so uma sequncia de operaes feitas em um sistema
gerenciador de banco de dados, tratadas de maneira coerente e convel, independente de outras transaes. As transaes tm o objetivo de isolar programas que
acessam um banco concorrentemente e proporcionar uma maneira de recuperar informaes a partir de um desastre. Uma transao de banco de dados deve possuir,
por denio, atomicidade, consistncia, isolamento e durabilidade (ACID).
Com transaes podemos garantir que sempre iremos manipular nosso banco de
dados de maneira convel. Por exemplo: estamos cadastrando uma compra em
nosso banco de dados. Alm de inserir as informaes de compra em uma tabela,
precisamos inserir e alterar informaes em outras tabelas, como a tabela de estoque, pedido, cliente e logstica. Caso haja um erro em qualquer um destes passos,
teramos um grande problema em mos. Imagine um problema na insero de informaes na tabela de logstica. O cliente pagou, tudo ocorreu aparantemente bem

Desenvolvimento Orientado a Objetos com PHP

Pgina 67

6.5 Transactions

4Linux www.4linux.com.br

para ele e para o sistema, mas no foi inserido o pedido de entrega na tabela de
logstica. E agora?

As transaes garantem que jamais teremos estes tipos de problema. Podemos


denir transaes em nossas aplicaes com o PDO utilizando o mtodo beginTransaction. Aps a chamada deste mtodo, todos os comandos feitos no sero automaticamente executados. O PDO ir aguardar pelo mtodo commit para executar os
comandos, ou pelo comando rollBack, para desfazer tudo que foi feito.

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

$db -> beginTransaction () ;

5
6

$db -> exec (" UPDATE pedidos SET compra = 5641 ");

$db -> exec (" UPDATE cliente SET compra = 5641 ");

$db -> exec (" INSERT INTO logistica ( compra ) VALUES (5641) ");

9
10

// Caso tudo tenha dado certo

11

$db -> commit () ;

12
13

// Ou caso tenha dado errado , podemos desfazer

14

$db -> rollBack () ;

Podemos vericar a consistncia de nossa operao de diversas formas. Uma aplicao pode ter falhas somente em suas queries, enquanto outras podem ter falhas
em diferentes pontos da transao.

Pgina 68

Desenvolvimento Orientado a Objetos com PHP

4Linux www.4linux.com.br

6.6 Prepared statements

6.6 Prepared statements


Prepared statements so comandos SQL pr-construdos, que podem ser manipulados utilizando parmetros variveis. Suas queries s precisam ser lidas uma nica
vez, enquanto so executadas mltiplas vezes com parmetros diferentes. Isso torna
a execuo da query muito mais rpida, agindo como um cache dinmico. Alm do
benefcio de performance, prepared statements garantem que nenhuma query que
foi preparada pode sofrer um ataque de SQL injection.
Imagine a insero de 300 registros em uma tabela. Quais so as nicas informaes
que mudam em cada query? As informaes de cada registro. A tabela e as colunas
no mudam. Um prepared statement criar um INSERT genrico, que vai inserir em
tabela e colunas pr-determinadas, enquanto apenas os valores iro mudar.
Para prepararmos nossas queries, o PDO possui um mtodo chamado prepare. Ele
muito similar aos mtodos exec e query, mas ao utiliz-lo, o comando no ser
executado, apenas preparado para ser executado posteriormente. O mtodo prepare retorna um objeto da classe PDOStatement. Quando criamos prepared statements, precisamos criar placeholders, ou substitutos. So como buracos, que sero
futuramente substitudos pelos valores que queremos que estejam naquela query.

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

4
5

$statement = $db -> prepare (" INSERT INTO posts ( titulo , conteudo )
VALUES (? , ?) ");

Observe as interrogaes em nossa query. Elas so nossos placeholders, que sero


substitudos mais tarde por variveis em nosso aplicao. Para executarmos um
comando preparado, usamos o mtodo execute, passando como parmetro um array
de variveis que sero substitudas pelos placeholders.

Desenvolvimento Orientado a Objetos com PHP

Pgina 69

6.7 Stored procedures

4Linux www.4linux.com.br

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

4
5

$statement = $db -> prepare (" INSERT INTO posts ( titulo , conteudo )
VALUES (? , ?) ");

6
7

$statement -> execute ( array (" Meu post " , " Meu primeiro post !"));

$statement -> execute ( array (" Outro post " , " Meu segundo post !"));

$statement -> execute ( array (" Mega post " , " Meu terceiro post !"));

Observe que temos apenas uma query, mas a executamos trs vezes, com trs valores diferentes. Estamos passando um array de informaes para o mtodo execute,
que pegar estas informaes e as colocar no lugar dos placeholders.

6.7 Stored procedures


Stored procedures so um conjunto de comandos SQL que podem ser armazenados
no sistema gerenciador de banco de dados. Uma vez que isso tenha sido feito, os
clientes no precisam reenviar os comandos individuais mas sim, fazer referncia
aos stored procedures. Isso pode resultar em um aumento de performance, j que
menos informaes so passadas entre nossa aplicao e o banco de dados, mas
em contrapartida, temos uma carga maior no banco de dados, para o processamento
dos dados.
O uso de stored procedures mais comum em operaes que exigem uma segurana muito grande, deixando as aplicaes de fora do processo e priorizando o
processamento de dados no prprio banco. Tambm comum o uso de stored procedures quando muitas aplicaes existem, escritas em diferentes linguagens e/ou
diferentes plataformas, mas que precisam executar as mesmas operaes em um

Pgina 70

Desenvolvimento Orientado a Objetos com PHP

4Linux www.4linux.com.br

6.7 Stored procedures

mesmo banco de dados.


Vamos criar uma simples procedure em nosso banco de dados:

DELIMITER $$

CREATE PROCEDURE listarposts ( IN _id INT )

BEGIN

IF ( _id IS NULL ) THEN

SELECT * FROM posts ;

ELSE

SELECT *

8
9
10

FROM posts where id = _id ;

END IF ;
END $$
DELIMITER ;

Observe que a denio de uma procedure similar a denio de uma funo.


Temos os delimitadores DELIMITER $$ e DELIMITER; que mostram que estamos
criando uma nova procedure. Usamos o comando CREATE PROCEDURE para criar
a procedure. Observe o comando entre parnteses, ele dene que esta procedure
pode receber um parmetro, assim como funes. Os parmetros de nossa procedure podem ser IN, apenas de entrada, OUT, apenas de sada e INOUT, entrada
e sada. Os tipos de dados dos parmetros so os mesmo tipos de dados que j
conhecemos (INT, VARCHAR, etc).
Vamos agora executar nossa procedure em nossa aplicao com o auxlio do PDO.
Para executar procedures, usamos o comando SQL CALL:

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

4
5

$statement = $db -> prepare (" CALL listarposts (?) ");

$um = $statement -> execute ( array (1) );

Desenvolvimento Orientado a Objetos com PHP

Pgina 71

6.8 Controle de erros


7

4Linux www.4linux.com.br

$todos = $statement -> execute () ;

8
9
10

print_r ( $um -> fetch () );


print_r ( $todos -> fetchAll () );

6.8 Controle de erros


Por padro, o PDO oferece trs modos de controle de erros. O primeiro deles,
PDO::ERRMODE_SILENT, o modo habilitado por padro. Neste modo, quando
houver qualquer problema durante a conexo ou comunicao com o banco de dados, o PDO no far nada, forando que voc implemente seu prprio controle de
erros com base nos mtodos errorCode e errorInfo. O segundo modo disponvel,
PDO::ERRMODE_WARNING, faz com que o PDO lance warnings toda vez que problemas sejam encontrados. Enquanto o terceiro modo, PDO::ERRMODE_EXCEPTION,
faz com que o PDO lance excees toda vez que problemas sejam encontrados.
Para congurarmos o modo de erro que queremos utilizar, vamos usar o mtodo
setAttribute. Este mtodo permite que conguremos uma instncia do PDO:

<? php

2
3

$db = new PDO (" mysql : host = localhost ; dbname = banco " , " root " , " 123456 " )
;

$db -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION );

Desta forma, podemos utilizar o PDO com nossos j conhecidos blocos de try e
catch:

<? php

Pgina 72

Desenvolvimento Orientado a Objetos com PHP

4Linux www.4linux.com.br
3

6.8 Controle de erros

try {

$db = new PDO (" mysql : host = lochsot ; dbname = banco " , " root " , " 123456 " )
;

5
6

$db -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION );


} catch ( PDOException $e ) {

7
8

echo " Falha na conex o: " . $e -> getMessage () ;


}

Desenvolvimento Orientado a Objetos com PHP

Pgina 73