Nesta lição, você otimiza o código para facilitar a manutenção dele no futuro. Isso afeta os arquivos createNewWisher.php e wishlist.php. Além disso, um novo arquivo chamado db.php é criado.
O código do seu aplicativo contém vários blocos de código semelhantes com consultas ao banco de dados. Para facilitar a leitura e a manutenção do código no futuro, você pode extrair esses blocos, implementá-los como funções de uma classe separada chamada WishDB e colocar WishDB em db.php. Depois disso, você pode incluir o arquivo db.php em qualquer arquivo PHP e usar qualquer função de WishDB sem duplicação de código. Essa abordagem garante que quaisquer alterações em consultas ou funções serão feitas em um único local e você não terá que analisar o código inteiro do aplicativo.
Quando usa uma função de WishDB, você não altera o valor de quaisquer variáveis de WishDB. Em vez disso, use a classe WishDB como um plano gráfico para criar um objeto de WishDB, e altere os valores das variáveis nesse objeto. Quando você termina de trabalhar com esse objeto, ele é destruído. Como os valores da classe WishDB em si nunca são alterados, você pode reutilizar a classe por um número ilimitado de vezes. Em alguns casos, talvez você queira ter várias instâncias de uma classe ao mesmo tempo, e em outros casos, talvez você prefira uma classe "única", onde você possui apenas uma instância de cada vez. WishDB neste tutorial é uma classe única.
Observe que o termo para criar um objeto de uma classe é "instanciar" essa classe, e que outra palavra para um objeto é uma "instância" de uma classe. O termo geral para programar com classes e objetos é "programação orientada a objeto" ou OOP. O PHP 5 usa um modelo OOP sofisticado. Consulte php.net para obter mais informações.
Neste tutorial, você move a funcionalidade de chamada do banco de dados dos arquivos PHP para a classe WishDB. Os usuários do MySQL também substituem as chamadas mysqli de procedimento por chamadas orientadas a objetos. Isso está de acordo com o novo design orientado a objeto do aplicativo.
O documento atual é uma parte do tutorial Criando um aplicativo CRUD no NetBeans IDE para PHP.
Código-fonte do aplicativo da lição anterior
Usuários do MySQL: clique aqui para baixar o código-fonte que reflete o estado do projeto depois que a lição anterior estiver concluída.
Usuários do banco de dados Oracle: clique aqui para baixar o código-fonte que reflete o estado do projeto depois que a lição anterior estiver concluída.
Criando o arquivo db.php
Crie uma nova subpasta na pasta Arquivos de código-fonte. Nomeie a pasta Includes. Crie uma novo arquivo denominado db.php e coloque-o em Includes. Mais tarde, é possível adicionar mais arquivos a esta pasta que será incluída em outros arquivos PHP.
Para criar db.php em uma nova pasta:
Clique com o botão direito do mouse no nó Arquivos de código-fonte no nó Arquivos de código-fonte e escolha Novo > Pasta no menu de contexto. A caixa de diálogo Nova pasta se abre.
No campo Nome da pasta, digite Includes. Clique em Terminar.
Clique com o botão direito do mouse no nó Inclusões e escolha Novo > Arquivo PHP no menu de contexto. A caixa de diálogo Novo arquivo PHP se abre.
No campo Nome do arquivo, digite db. Clique em Terminar.
Criando a classe WishDB
Para criar a classe WishDB, você precisa inicializar as variáveis da classe e implementar um construtor da classe. Os usuários do MySQL devem observar que a classe WishDB estendemysqli. Isso significa que WishDB herda as funções e outras características da classe mysqli do PHP. Você verá a importância disso quando adicionar funções mysqli à classe.
Abra o arquivo db.php e crie a classe WishDB. Na classe, declare variáveis de configuração de banco de dados para armazenar o nome e a senha do proprietário do banco de dados (usuário), o nome do banco de dados e o host do banco de dados. Todas essas declarações de variável são "privadas", o que significa que os valores iniciais nas declarações não podem ser acessados de fora da classe WishDB (Consulte php.net). Você também declara a variável privada estática$instance, que armazena a instância de WishDB. A palavra-chave "estática" significa que as funções da classe podem acessar a variável mesmo quando não houver nenhuma instância da classe.
No banco de dados MySQL:
class WishDB extends mysqli {
// single instance of self shared among all instances
private static $instance = null;
// db connection config vars
private $user = "phpuser";
private $pass = "phpuserpw";
private $dbName = "wishlist";
private $dbHost = "localhost";
}
No banco de dados Oracle:
class WishDB {
// single instance of self shared among all instances
private static $instance = null;
Para outros arquivos PHP usarem funções na classe WishDB, esses arquivos PHP precisam chamar uma função que crie um objeto ("instantiates") da classe WishDB. WishDB é designado como uma classe única, o que significa que somente uma instância da classe existe de cada vez. Portanto, é útil evitar qualquer instanciação externa de WishDB, o que poderia criar instâncias duplas.
Dentro da classe WishDB, digite ou cole o seguinte código:
//This method must be static, and must return an instance of the object if the object
//does not already exist.
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
// The clone and wakeup methods prevents external instantiation of copies of the Singleton class,
// thus eliminating the possibility of duplicate objects.
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Deserializing is not allowed.', E_USER_ERROR);
}
A função getInstance é "pública" e "estática." "Pública" significa que ela pode ser acessada publicamente de fora da classe. "Estática" significa que a função está disponível mesmo quando a classe não tiver sido instanciada. Como a função getInstance é chamada para instanciar a classe, ela deve ser estática. Observe que esta função acessa a variável estática $instance e define seu valor como a instância da classe.
Os dois pontos (::), chamados de Operador de resolução de escopo, e a palavra-chave self são usados para acessar funções estáticas. Self é usada na definição da classe para se referir à classe em si. Quando os dois pontos forem usados de fora da definição da classe, o nome da classe será usado em vez de self. Consulte php.net no Operador de resolução de escopo.
Adicionando um construtor à classe WishDB
Uma classe pode conter um método especial conhecido como 'construtor' que é processado automaticamente sempre que uma instância dessa classe é criada. Neste tutorial, você adiciona um construtor ao WishDB que se conecta ao banco de dados sempre que WishDB é instanciado.
Observe o uso da pseudovariável $this em vez das variáveis $con, $dbHost, $user ou $pass. A pseudovariável $this é usada quando um método é chamado de dentro do contexto de um objeto. Ela se refere ao valor de uma variável nesse objeto.
Funções na classe WishDB
Nesta lição, você implementará as seguintes funções da classe WishDB:
get_wisher_id_by_name para recuperar o id de um criador de lista de desejos com base em seu nome
get_wishes_by_wisher_id para recuperar uma lista de desejos do criador de lista de desejos com um id específico
create_wisher para adicionar um novo registro do criador de lista de desejos de código aos criadores da tabela
Função get_wisher_id_by_name
A função requer o nome de um criador de lista de desejos e retorna o id do criador.
Digite ou cole a seguinte função na classe WishDB, depois da função WishDB:
No banco de dados MySQL:
public function get_wisher_id_by_name($name) {
$name = $this->real_escape_string($name);
$wisher = $this->query("SELECT id FROM wishers WHERE name = '"
. $name . "'");
if ($wisher->num_rows > 0){ $row = $wisher->fetch_row(); return $row[0]; } else return null;
}
No banco de dados Oracle:
public function get_wisher_id_by_name($name) {
$query = "SELECT id FROM wishers WHERE name = :user_bv";
$stid = oci_parse($this->con, $query);
oci_bind_by_name($stid, ':user_bv', $name);
oci_execute($stid);
//Because user is a unique value I only expect one row
$row = oci_fetch_array($stid, OCI_ASSOC); if ($row) return $row["ID"]; else return null;
}
O bloco de código executa a consulta SELECT ID FROM wishers WHERE name = [variável do nome do criador da lista de desejos]. O resultado da consulta é uma matriz de IDs dos registros que atendem à consulta. Se a matriz não estiver vazia, isso significa automaticamente que ela contém um elemento porque o nome do campo é especificado como ÚNICO durante a criação da tabela. Nesse caso, a função retorna o primeiro elemento da matriz $result (o elemento com zero). Se a matriz estiver vazia a função retorna nulo.
Observação de segurança: no banco de dados MySQL, a string $name tem escape para evitar os ataques de injeção SQL. Consulte Wikipedia sobre injeções SQL e a documentação mysql_real_escape_string. Embora no contexto deste tutorial você não esteja correndo o risco de injeções SQL prejudiciais, recomendamos escapar as strings nas consultas MySQL que estariam correndo risco de tal ataque. O banco de dados Oracle evita este problema utilizando as variáveis de ligação.
Função get_wishes_by_wisher_id
A função requer o id de um criador de lista de desejos como o parâmetro de entrada e retorna os desejos registrados para o criador de lista de desejos.
Indique o seguinte bloco de código:
No banco de dados MySQL:
public function get_wishes_by_wisher_id($wisherID) { return $this->query("SELECT id, description, due_date FROM wishes WHERE wisher_id=" . $wisherID); }
No banco de dados Oracle:
public function get_wishes_by_wisher_id($wisherID) {
$query = "SELECT id, description, due_date FROM wishes WHERE wisher_id = :id_bv";
$stid = oci_parse($this->con, $query);
oci_bind_by_name($stid, ":id_bv", $wisherID);
oci_execute($stid);
return $stid;
}
O bloco de código executa a consulta "SELECT id, description, due_date FROM wishes WHERE wisherID=" . $wisherID e retorna um conjunto de resultados que é uma matriz de registros que atende à consulta. (O banco de dados Oracle utiliza uma variável de ligação por questão de desempenho e segurança do banco de dados.) A seleção é realizada pelo wisherID, que é a chave estrangeira para a tabela de desejos.
Nota: não é necessário o valor de id até a Lição 7.
Função create_wisher
A função cria um novo registro na tabela dos criadores de lista de desejos. A função requer o nome e a senha de um novo criador de lista de desejos como os parâmetros de entrada e não retorna quaisquer dados.
Indique o seguinte bloco de código:
No banco de dados MySQL:
public function create_wisher ($name, $password){
$name = $this->real_escape_string($name); $password = $this->real_escape_string($password); $this->query("INSERT INTO wishers (name, password) VALUES ('" . $name . "', '" . $password . "')");
}
No banco de dados Oracle:
public function create_wisher($name, $password) {
$query = "INSERT INTO wishers (name, password) VALUES (:user_bv, :pwd_bv)";
$stid = oci_parse($this->con, $query);
oci_bind_by_name($stid, ':user_bv', $name);
oci_bind_by_name($stid, ':pwd_bv', $password);
oci_execute($stid);
}
O bloco de código executa a consulta "INSERT wishers (Name, Password) VALUES ([variáveis representando o nome e a senha do novo criador da lista de desejos]). A consulta adiciona um novo registro à tabela "wishers" com os campos "name" e "password" preenchidos com os valores de $name e $password respectivamente.
Refatorando o código do seu aplicativo
Agora que tem uma classe separada para trabalhar com o banco de dados, você pode substituir blocos duplicados por chamadas para as funções relevantes a partir desta classe. Isso ajudará a evitar erro ortográfico e inconsistência no futuro. A otimização de código que não afeta a funcionalidade é chamada de refatoração.
Refatorando o arquivo wishlist.php
Comece com o arquivo wishlist.php porque ele é pequeno e as melhorias serão mais ilustrativas.
Na parte superior do bloco <?php ?> , indique a linha seguinte para permitir o uso do arquivo db.php:
require_once("Includes/db.php");
Substitua o código que se conecta ao banco de dados e obtenha o ID do criador da lista de desejos com uma chamada à função get_wisher_id_by_name.
No banco de dados MySQL, o código substituído é:
$con = mysqli_connect("localhost", "phpuser", "phpuserpw");
if (!$con) {
exit('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
//set the default client character set
mysqli_set_charset($con, 'utf-8');
mysqli_select_db($con, "wishlist");
$user = mysqli_real_escape_string($con, $_GET['user']);
$wisher = mysqli_query($con, "SELECT id FROM wishers WHERE name='" . $usuário . "'");
if (mysqli_num_rows($wisher) < 1) {
exit("The person " . $_GET['user'] . " is not found. Please check the spelling and try again");
}
$row = mysqli_fetch_row($wisher); $wisherID = $row[0];
mysqli_free_result($wisher);
$wisherID = WishDB::getInstance()->get_wisher_id_by_name($_GET["user"]);
if (!$wisherID) {
exit("The person " .$_GET["user"]. " is not found. Please check the spelling and try again" );
}
No banco de dados Oracle, o código substituído é:
$con = oci_connect("phpuser", "phpuserpw", "localhost/XE", "AL32UTF8");
if (!$con) {
$m = oci_error();
echo $m['message'], "\n";
exit;
}
$query = "SELECT id FROM wishers WHERE name = :user_bv";
$stid = oci_parse($con, $query);
$user = $_GET["user"];
oci_bind_by_name($stid, ':user_bv', $user);
oci_execute($stid);
//Because user is a unique value I only expect one row
$row = oci_fetch_array($stid, OCI_ASSOC);
if (!$row) {
echo("The person " . $usuário . " is not found. Please check the spelling and try again" ); exit;
}
$wisherID = $row["ID"]; $wisherID = WishDB::getInstance()->get_wisher_id_by_name($_GET["user"]);
if (!$wisherID) {
exit("The person " .$_GET["user"]. " is not found. Please check the spelling and try again" );
}
O novo código chama primeiro a função getInstance em WishDB. A função getInstance retorna uma instância de WishDB, e o código chama a função get_wisher_id_by_name dentro desta instância. Se o criador da lista de desejos solicitado não for encontrado no banco de dados, o código elimina o processo e exibe uma mensagem de erro.
Nenhum código é necessário para abrir uma conexão ao banco de dados. A conexão é aberta pelo construtor da classe WishDB. Se o nome e/ou a senha for alterado, você precisará atualizar somente as variáveis relevantes da classe WishDB.
Substitua o código que obtém os desejos do criador identificado pelo ID pelo código que chama a função get_wishes_by_wisher_id.
No banco de dados MySQL, o código substituído é:
$result = mysqli_query($con, "SELECT description, due_date FROM wishes WHERE wisher_id=" . $wisherID);$result = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);
No banco de dados Oracle, o código substituído é:
$query = "select * from wishes where wisher_id = :id_bv"; $stid = oci_parse($con, $query); oci_bind_by_name($stid, ":id_bv", $wisherID); oci_execute($stid);$stid = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);
Remova a linha que fecha a conexão ao banco de dados.
mysqli_close($con);
ou
oci_close($con);
O código não é necessário porque a conexão ao banco de dados é automaticamente fechada quando o objeto WishDB é destruído. No entanto, mantenha o código que libera o recurso. É necessário liberar todos os recursos que utilizam uma conexão para garantir que a conexão seja fechada corretamente, mesmo se a função close for chamada o a instância com a conexão ao banco de dados for destruída.
Refatorando o arquivo createNewWisher.php
A refatoração não afetará o formulário de entrada HTML ou o código para exibir as mensagens de erro relacionadas.
Na parte superior do bloco <?php ?>, indique o código seguinte para permitir o uso do arquivo db.php:
require_once("Includes/db.php");
Exclua a as credenciais da conexão ao banco de dados ($dbHost, etc). Tais credenciais estão agora no db.php.
Substitua o código que se conecta ao banco de dados e obtenha o ID do criador da lista de desejos com uma chamada à função get_wisher_id_by_name.
No banco de dados MySQL, o código substituído é:
$con = mysqli_connect("localhost", "phpuser", "phpuserpw");
if (!$con) {
exit('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
//set the default client character set
mysqli_set_charset($con, 'utf-8');
/** Check whether a user whose name matches the "user" field already exists */
mysqli_select_db($con, "wishlist");
$user = mysqli_real_escape_string($con, $_POST['user']);
$wisher = mysqli_query($con, "SELECT id FROM wishers WHERE name='".$usuário."'");
$wisherIDnum=mysqli_num_rows($wisher);
if ($wisherIDnum) {
$userNameIsUnique = false;
} $wisherID = WishDB::getInstance()->get_wisher_id_by_name($_POST["user"]); if ($wisherID) { $userNameIsUnique = false; }
No banco de dados Oracle, o código substituído é:
$con = oci_connect("phpuser", "phpuserpw", "localhost");
if (!$con) {
$m = oci_error();
echo $m['message'], "\n";
exit;
}
$query = "select ID from wishers where name = :user_bv";
$stid = oci_parse($con, $query);
$user = $_POST['user'];
$wisherID = null;
oci_bind_by_name($stid, ':user_bv', $user);
oci_execute($stid);
//Each user name should be unique. Check if the submitted user already exists.
$row = oci_fetch_array($stid, OCI_ASSOC); if ($row) { $wisherID = $row["ID"]; } if ($wisherID != null) { $userNameIsUnique = false; }$wisherID = WishDB::getInstance()->get_wisher_id_by_name($_POST["user"]); if ($wisherID) { $userNameIsUnique = false; }
O objeto WishDB existe enquanto a página atual está sendo processada. Ele é destruído depois que o processamento é concluído ou interrompido. O código para abrir uma conexão ao banco de dados não é necessário porque isso é feito pela função WishDB. O código para fechar a conexão não é necessário porque a conexão é fechada assim que o objeto WishDB é destruído.
Substitua o código que insere os novos criadores de lista de desejos no banco de dados com o código que chama a função create_wisher.
Para enviar comentários e sugestões, obter suporte e manter-se informado sobre os desenvolvimentos mais recentes dos recursos de desenvolvimento em PHP no NetBeans IDE, junte-se à lista de usuários .