corner imagecorner image
IDEPlatformPluginsDocs & SupportCommunityPartners

Criando um aplicativo direcionado a banco de dados com o PHP

Lição 4: Otimizando o código com classes e objetos

O conteúdo desta página se aplica ao NetBeans IDE 6.9-7.0O conteúdo desta página se aplica ao NetBeans IDE 6.9-7.0" title="

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.

Nesse tutorial, a funcionalidade de chamada do banco de dados é movida de arquivos PHP individuais para classes WishDB. Usuários do MySQL podem substituir a chamada mysqli de estilo de procedimento por chamadas orientadas por objetos. Isso é para mantar com o novo projeto orientado por objetos 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 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 subpasta na pasta Source Files. Nomeie a pasta Includes. Crie uma nova pasta nomeada db.php e coloque em Includes. Posteriormente é possível adicionar mais arquivos para essa pasta que será incluída em outros arquivos PHP.

Para criar o db.php em uma nova pasta:

  1. 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 é aberta.
  2. No campo Nome da pasta, digite Includes. A seguir, clique em Terminar.
  3. 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 é aberta.
  4. No campo Nome do arquivo, digite db. A seguir, 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. Usuários MySQL observem a classe WishDB extends mysqli. Isso significa que o WishDB herda a função e outras características da classe mysqli PHP. A importância disso é mostrada ao adicionar as 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). Declare também a variável static $instance privada, que armazena a instância do WishDB. A palavra-chave “estática” significa que a função na classe pode acessar a variável mesmo quando não há instância da classe.

Para 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";
}

Para Banco de dados Oracle

class WishDB {

// 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/XE"; private $con = null;

}

Instanciando a classe WishDB

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 essa função acessa a variável$instance estática e ajusta os valores 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.

Adicione o código seguinte ao WishDB:

Para o banco de dados MySQL:

// private constructor
private function __construct() {
parent::__construct($this->dbHost, $this->user, $this->pass, $this->dbName);
if (mysqli_connect_error()) {
exit('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
parent::set_charset('utf-8');
}

Para o banco de dados Oracle:

// private constructor
private function __construct() {
    $this->con = oci_connect($this->user, $this->pass, $this->dbHost);
    if (!$this->con) {
        $m = oci_error();
        echo $m['message'], "\n";
        exit;
    }
}

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:

Para o 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; }

Para o 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 = [variable for name of the wisher]. 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 par ao 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 esse problema usando 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:

Para o 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);
}

Para o 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=" . $wisherIDe retorna um conjunto de resultados que é uma matriz de registros que atende à consulta. (O banco de dados Oracle usa variáveis de ligação para o desempenho do banco de dados e motivos de segurança). A seleção é realizada pelo wisherID, que é a chave estrangeira dos desejos da tabela.

Observação: o valorid não é necessário 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:

Para o 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 . "')"); }

Para o 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 ([variables representing name and password of new wisher]). 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.
  1. Na parte superior do bloco <?php ?> , indique a linha seguinte para permitir o uso do arquivo db.php:
    require_once("Includes/db.php");
  2. Substitua o código que conecta com o banco de dados e que obtém a ID do desejo com uma chamada para a função get_wisher_id_by_name.

    Para o banco de dados MySQL, o código a ser 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='" . $user . "'");
    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(htmlentities($_GET["user"])); if (!$wisherID) { exit("A pessoa " .htmlentities($_GET["user"]). " is not found. Please check the spelling and try again" ); }

    Para o banco de dados Oracle, o código a ser 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 = htmlentities($_GET["user"]);
    
    oci_bind_by_name($stid, ':user_bv', $user);
    oci_execute($stid);
    
    //Pois user é um valor exclusivo que, eu espero somente uma linha
    $row = oci_fetch_array($stid, OCI_ASSOC); if (!$row) { echo("The person " . $user . " is not found. Please check the spelling and try again" );
    exit;
    } $wisherID = $row["ID"];

    $wisherID = WishDB::getInstance()->get_wisher_id_by_name(htmlentities($_GET["user"])); if (!$wisherID) { exit("A pessoa " .htmlentities($_GET["user"]). " is not found. Please check the spelling and try again" ); }

    O novo código chama primeiro a função getInstance em WishDB. O getInstance retorna uma instância de WishDB, e o código chama a função get_wisher_id_by_name dentro dessa instância. Se a lista de desejos solicitada não for encontrada no banco de dados, o código terminará o processo, e exibirá 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.

  3. Substitua o código que recebe desejos de um identificador desejo por ID com um código que chama a função get_wishes_by_wisher_id.

    Para o banco de dados MySQL, o código a ser 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);

    Para o banco de dados Oracle, o código a ser 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);
  4. Remova a linha que fecha a conexão do 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 usam uma conexão para garantir que a conexão é fechada corretamente, mesmo quando a função close é chamada ou se a instância for destruída com a conexão do banco de dados.

 

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.

  1. Na parte superior do bloco <?php ?>, indique o código seguinte para permitir o uso do arquivo db.php:
    require_once("Includes/db.php");
  2. Exclua a credencial da conexão do banco de dados ($dbHost, etc). Esses estão agora em db.php..
  3. Substitua o código que conecta com o banco de dados e que obtém a ID do desejo com uma chamada para a função get_wisher_id_by_name.

    Para o banco de dados MySQL, o código a ser 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='".$user."'"); $wisherIDnum=mysqli_num_rows($wisher); if ($wisherIDnum) { $userNameIsUnique = false; }

    $wisherID = WishDB::getInstance()->get_wisher_id_by_name($_POST["user"]);
    if ($wisherID) {
    $userNameIsUnique = false;
    }

    Para o banco de dados Oracle, o código a ser 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);
    
    //Cada nome de usuário deve ser único. Verifique se o usuário enviado já existe.
    $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.
  4. Substitua o código que insere novos desejos no banco de dados pelo código que chama a função create_wisher.

    Para o banco de dados MySQL, o código a ser substituído é:

    if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty && $passwordIsValid) {
        $password = mysqli_real_escape_string($con, $_POST["password"]);
    mysqli_select_db($con, "wishlist");
    mysqli_query($con, "INSERT wishers (name, password) VALUES ('" . $user . "', '" . $password . "')");
    mysqli_free_result($wisher);
    mysqli_close($con);
    header('Location: editWishList.php' );
    exit;
    }
    if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty && $passwordIsValid) {
    WishDB::getInstance()->create_wisher($_POST["user"], $_POST["password"]);
    header('Location: editWishList.php' );
    exit;
    }

    Para o banco de dados Oracle, o código a ser substituído é:

    
    if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty && $passwordIsValid) {
        $query = "INSERT INTO wishers (name, password) VALUES (:user_bv, :pwd_bv)";
        $stid = oci_parse($con, $query);
        $pwd = $_POST['password'];
        oci_bind_by_name($stid, ':user_bv', $user);
        oci_bind_by_name($stid, ':pwd_bv', $pwd);
        oci_execute($stid);
        oci_close($con);
        header('Location: editWishList.php');
        exit;
    }
    
    
    if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty && $passwordIsValid) {
    WishDB::getInstance()->create_wisher($_POST["user"], $_POST["password"]);
    header('Location: editWishList.php' );
    exit;
    }

O código-fonte do aplicativo após a lição atual está concluído

Usuários do MySQL: Clique aqui para baixar o código-fonte que reflete o estado do projeto depois que a lição 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 estiver concluída.

Próximas etapas

<< Lição anterior

Próxima lição >>

Voltar à página principal do tutorial

Links úteis

Saiba mais sobre o uso de classes em PHP:

Saiba mais sobre a refatoração de código PHP:



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 .

Voltar à trilha do aprendizado PHP