-
Notifications
You must be signed in to change notification settings - Fork 1
2.4.3 PHP Data Objects(PDO)
O PDO veio para solucionar a migração de um banco de dados para outro, do MySQL para o PostgreSQL, por exemplo. O PDO é uma camada de abstração de acesso a dados, onde os métodos de manipulação de dados são independentes do SGDB que você está utilizando, ou seja, podemos usar as mesmas funções para executar queries e consultar dados. O PDO veio no PHP 5.1 e dá suporte a vários sistemas gerenciadores de banco de dados, como MySQL, PostgreSQL, SQlite, Informix, Oracle, SQL Server, IBM e etc. A conexão com um banco de dados através do PDO se dá durante a criação de um objeto da classe PDO, passando informações de conexão com o banco na forma de um DSN (Data Source Name), além das credencias de acesso, como mostra o próximo exemplo.
<?php
// MySQL
$db= new PDO("mysql:host=localhost;dbname=banco", "root", "senha");
// PostgreSQL
$db = new PDO("pgsql:host=localhost;dbname=banco", "root", "senha");
// SQLite
$db = new PDO("sqlite:banco.sqlite");
?>
Veja que criamos a $db que guarda um objeto da classe PDO e entre parênteses passamos o host, nome do banco, usuário e senha. Uma vez que o objeto da classe PDO tenha sido instanciado, conectamos em nosso banco. Para desconectar, basta "matarmos" o objeto ou aguardar que ele seja morto automaticamente ao final de nosso script, como podemos ver a seguir:
<?php
$db = new PDO("mysql:host=localhost;dbname=banco", "root", ""); //É recomendado que a instância do PDO seja passada por parâmetro.
unset($db);
?>
Veja que utilizamos o unset para encerrar a conexão.
Depois de conectados temos a nossa disposição uma série de métodos para lidar com o banco. Utilizando a linguagem SQL, vamos fazer o uso do método exec, de acordo com o código do próximo exemplo.
<?php
$db = new PDO("mysql:host=localhost;dbname=banco", "root", ""); //É recomendado que a instância do PDO seja passada por parâmetro.
$db->exec("CREATE TABLE clientes(id INT AUTO_INCREMENT, nome VARCHAR(255), email VARCHAR(255)) ");
?>
Veja que acessamos o método exec através de nossa conexão com o “->” e criamos uma tabela chamada clientes com os campos id, nome e email.
Para fazer consultas usamos o método query, que executa um comando SQL e traz para nós linhas de um banco de dados. Veja o próximo exemplo.
<?php
$db = new PDO("mysql:host=localhost;dbname=banco", "root", ""); //É recomendado que a instância do PDO seja passada por parâmetro.
$dados = $db->query("SELECT * FROM clientes");
?>
Veja que dentro da $dados é executada uma query que traz todos os dados da tabela clientes. Podemos ainda acessar nossos dados através dos métodos fetch e fetchAll. O método fetch retorna apenas um resultado para nós, enquanto o fetchAll irá retornar todos os resultados. Estes métodos retornam tanto um array quando um objeto, dependendo dos parâmetros especificados, como exemplo a seguir.
<?php
$db = new PDO("mysql:host=localhost;dbname=banco", "root",""); //É recomendado que a instância do PDO seja passada por parâmetro.
$dados = $db->query("SELECT * FROM clientes");
$todos = $dados->fetchAll();
$um = $dados->fetch();
print_r($todos);
print_r($um);
?>
Note que, por padrão, os métodos retornam índices associativos e numéricos. Podemos fazer com que somente índices associativos sejam mostrados ou apenas numéricos, como mostra o código a seguir
<?php
$db = new PDO("mysql:host=localhost;dbname=banco", "root",""); //É recomendado que a instância do PDO seja passada por parâmetro.
$dados = $db->query("SELECT * FROM clientes");
$assoc = $dados->fetchAll(PDO::FETCH_ASSOC);
$num = $dados->fetchAll(PDO::FETCH_NUM);
print_r($assoc);
print_r($num);
?>
Veja que na $assoc queremos que seja retornado resultados em índices associativos, enquanto que na $num retorna apenas índices numéricos.
Transações são uma sequência de operações feitas em um sistema gerenciador de banco de dados. As transações têm o objetivo de proporcionar uma maneira de recuperar informações a partir de um desastre. Uma transação de banco de dados deve possuir atomicidade, consistência, isolamento e durabilidade (ACID).
Imagine um sistema onde temos que inserir dados em tabelas de estoque, pedido, cliente e logística. O cliente pagou e tudo foi inserido aparentemente bem no sistema, mas não foi inserido o pedido de entrega na tabela de logística. Temos um problema agora, certo?!
As transações evitam esse tipo de problema através do método beginTransaction do PDO. Utilizamos do try-catch, que simplificando seria como: tente, falhando, pegue. No try, após chamarmos o método, os comandos serão feitos para que possam ser executados. O PDO irá esperar pelo método commit para efetivar os comandos no banco de dados. Entretanto pode ocorrer erros e nem todos os comandos serão efetuados, neste caso entramos no catch, no qual será tratado o comando rollback para anular os comandos e desfazer tudo que foi feito. Veja o próximo exemplo.
<?php
$db = new PDO("mysql:host=localhost;dbname=banco", "root", ""); // É recomendado que a instância do PDO seja passada por parâmetro.
try {
$db->beginTransaction();
$db->exec("UPDATE pedidos SET compra = 5641");
$db->exec("UPDATE clientes SET compra = 5641 ");
$db->exec("INSERT INTO logística(compra) VALUES (5641)");
$db->commit();
// Caso tudo tenha dado certo
} catch (Exception $e) {
$connection->rollback();
return false;
// Caso não deu certo $db->rollback();
}
Statements são comandos SQL pré-construídos e garantem que nenhuma query que foi preparada sofra um ataque SQL injection, ou seja, um ataque baseado na manipulação do código SQL pela inserção de informações em uma query.
- Prepare
O PDO possui um método chamado prepare que, ao utilizá-lo, tem como idéia apenas iniciar a query e aguardar pela inclusão de valores posteriormente, ou sejam, o comando não será executado, apenas preparado para ser executado depois. O método prepare retorna um objeto da classe PDOStatement para que, quando utilizamos esse método, precisamos criar placeholders que serão substituídos pelos valores que queremos que estejam naquela query. Veja o próximo exemplo.
public function on($connect) {
$stm = $connect->prepare("SELECT * FROM `users` WHERE email = :email AND password = :password LIMIT 1");
$stm->BindValue(":email", $this->email, PDO::PARAM_STR);
$stm->BindValue(":password", $this->password, PDO::PARAM_STR);
$stm->execute();
return $stm -> fetch(PDO::FETCH_ASSOC);
}
Neste caso, foi criada uma função on, que pode ser executada após se instanciar um objeto do tipo Login. A função on espera receber como atributo o $connect (veremos que $connect vai ter uma classe, onde tem uma função que contém uma instância de um objeto do tipo PDO).
Na primeira linha da função utilizamos o método prepare da classe PDO, o método prepare é utilizado com a ideia de apenas iniciar a query e aguardar pela inclusão de valores posteriormente.
No nosso caso a query é um comando MySQL de seleção que, em português, está dizendo: “Selecione tudo da(s) linha(s) da tabela users onde o campo email for igual ao parâmetro :email e o campo password for igual ao parâmetro :password, com o limite de uma linha.” Se o servidor de banco de dados preparar o comunicado com êxito, o prepare retorna um objeto PDOStatement que é armazenado em $stm. Se o servidor de banco de dados não pode se preparar com êxito, a declaração retorna FALSE.
- BindValue
Tomando como base o último exemplo, após o prepare, temos acesso ao método BindValue do PDOStatement, a função dele é vincular um valor a um parâmetro. No nosso caso, temos que o parâmetro :email passa a ter o valor atual da nossa propriedade $email, bem como :password passa a ter o valor de $password. O PDO::PARAM_ define o tipo de dado que está sendo passado, confira TODOS.
$stm -> BindValue(":email", $this -> email, PDO::PARAM_STR);
$stm -> BindValue(":password", $this -> password, PDO::PARAM_STR);
- Execute
Em seguida, temos mais um método de PDOStatement, o execute, que como o nome indica, executa um declaração preparada.
$stm -> execute();
- Fetch
Por fim, retornamos o resultado do método fetch do PDOStatement. O método fetch retorna uma linha de um conjunto de resultados associado a um objeto PDOStatement. O PDO::FETCH_ determina a forma como o fetch vai retornar o resultado, confira http://php.net/manual/pt_BR/pdostatement.fetch.php.
return $stm -> fetch(PDO::FETCH_ASSOC);
<?php
class Connect {
protected static function start()
{
$pdo = new PDO('mysql:host=localhost;dbname=git-github', 'root', '');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $pdo;
}
}
?>
No arquivo connect veremos que ele passa a ter uma classe, onde tem uma função que contém uma instância de um objeto do tipo PDO. Utilizamos o arquivo connect como uma classe para que ela possa ser atribuída como herança em outras classes. Veja o exemplo:
public function insert() {
$connect = static::start();
$stm = $connect->prepare("INSERT INTO users(name, email, phone, registry, semester, course, status) VALUES (:name, :email, :phone, :registry, :semester, :course, :status)");
$stm->BindValue(":name", $this->name, PDO::PARAM_STR);
$stm->BindValue(":email", $this->email, PDO::PARAM_STR);
$stm->BindValue(":phone", $this->phone, PDO::PARAM_STR);
$stm->BindValue(":registry", $this->registry, PDO::PARAM_INT);
$stm->BindValue(":semester", $this->semester, PDO::PARAM_INT);
$stm->BindValue(":course", $this->course, PDO::PARAM_STR);
$stm->BindValue(":status", $this->status, PDO::PARAM_INT);
return $stm->execute();
}
Na primeira linha da nossa classe connect temos o static que é usado para definir que um método ou atributo em uma classe é estático. Isso significa que aquele método/atributo pertence à classe e não à uma instância dela e, por isso, pode ser acessado sem instânciar um novo objeto. Dentro da função start, instanciamos um novo objeto PDO, e armazenamos no $pdo. Os parâmetros passados são: a linguagem do banco de dados e o host, o nome do banco de dados, o usuário do bd e a senha, que no nosso caso está em branco. Daí utilizamos o método setAttribute para dizer o modo como erro vai ser reportado.