Inicial > Banco de dados, MySQL, oop, PHP, Programação orientada a objetos > Uma classe PHP-MySQL usando mysqli:__constructor e __destructor

Uma classe PHP-MySQL usando mysqli:__constructor e __destructor

 

Introdução

Programar é uma tarefa difícil. Difícil e trabalhosa. É uma arte, que exige experiência, dedicação, conhecimento, habilidade, criatividade, etc. O presente texto mostra, aos interessados, como preparar uma classe para manipular tabelas em bases de dados.

Há três recomendações para tornar a difícil arte, menos traumática:

  1. Refinamentos sucessivos
  2. Programação estruturada
  3. Programação Orientada a Objetos

Além das recomendações acima, a disciplina e o conhecimento das técnicas associadas a linguagens específicas são fundamentais. E as ferramentas, finalmente. Para base de dados uso o MySQL Workench e o MySQL Administator. Para editar os programas em PHP, uso o PHPDezigner e o Enterprise Architect para modelar meus projetos de desenvolvimento, em UML (Unified Modeling Language). Uso UML, também, para modelagem de negócios e modelagem de topologias de redes, de longa distância ou complexas, sobre as quais aplica-se os protocolos BGP, OSPF, RIP e associados (MPLS, por exemplo). A UML é ótima para modelar, inclusive, os componentes dinâmicos envolvidos em tais protocolos. Falo sobre tais ferramentas não porque sejam as melhores. As melhores ferramentas são aquelas com as quais você projeta e desenvolve seu estilo, de forma gratificante.

O principal objetivo deste trabalho é o desenvolvimento de programação orientada a objetos, em PHP. Usaremos o método direto, onde a didática tem valor significativo. Não é um texto para programadores muito experientes. É um texto para os iniciantes ou aqueles experientes interessados no aperfeiçoamento pessoal.

Construção da classe

Inicio as classes, usualmente, com três componentes: a propriedade (variável) que irá identificar o número de instâncias abertas, e os métodos construtor e destrutor. O método construtor conta as instâncias. E, um pequeno programa serve para testar cada etapa do processo de refinamento sucessivo. Eis a primeira versão, abaixo:

<?php
// Versão 1
class BancodeDados extends mysqli {
    
    static $idBancodeDados = 0;
    
    /**
     * Construtor:
     * 
     * 1. Conta o número de instâncias.
    */
    
    public function __construct() {
        self::$idBancodeDados++;        
    }
    
    public function __destruct() {
        --self::$idBancodeDados;
    }
}

Eis o teste e respectivo resultado:

<?php
// Versão 1
require_once ('../includes/funcoesgerais.phpm');
require_once ('../includes/db.phpm');

$db_faleok = new db();
echo "
Instâncias abertas: " . BancodeDados::$idBancodeDados; $db_faleok1 = new db(); echo "
Instâncias abertas: " . BancodeDados::$idBancodeDados; ?> Instâncias abertas: 1 Instâncias abertas: 2

O interessante a observar acima são os seguintes pontos:

  • A propriedade estática $idBancodeDados é incrementada no método __construtor, que como sabemos é executado na criação de uma instância da classe BancodeDados.
  • Uma propriedade estática é referenciada externamente como NomedaClasse::$NomedaPropriedade, pois ela pertence à própria classe.
  • A classe BancodeDados, herda métodos e funções da classe msqli, do PHP, uma vez que estamos usando extends mysqli, na sua declaração.
  • É bom lembrar, que o método __constructor não pode retornar valores. Esta noção será muito útil mais à frente. Entretanto pode-se observar que o exemplo acima ele altera o valor de uma propriedade estática, isto é, $idBancodeDados, que é como se fosse uma variável global.
  • O trecho:
    /**
     * Construtor:
     *
     * 1. Conta o número de instâncias.
    */
    

    é a documentação da classe. Como uso o phpdoc esta tarefa torna-se, em particular, muito importante.

Não se pode esquecer do registro de atividades. Foi construída uma classe chamada Mensagens que possui dois métodos. Um método exibe uma mensagem na tela, como acima, e o outro, grava a mensagem em um arquivo de “log”. Embora a classe Mensagens não seja exibida aqui (assim como outras que não a classe BancodeDados), o contexto a deixa claro. Eis como fica a versão 2 e seu resultado:

<?php
$db_faleok1 = new BancodeDados();
Mensagem = "Instâncias abertas: " . BancodeDados::$idBancodeDados;
$msg->Exibe();
$msg->LogFaleOK();

$db_faleok2 = new BancodeDados();
$msg->Mensagem = "Instâncias abertas: " . BancodeDados::$idBancodeDados;
$msg->Exibe();
$msg->LogFaleOK();

?>

20120121 11:55:43 - Instâncias abertas: 1
20120121 11:55:43 - Instâncias abertas: 2

As observações sobre a Versão 2 do teste são:

  • Aperfeiçoamos o nome das instâncias da classe BancodeDados, dando mais consistência visual ($db_faleok1 e $db_faleok2).
  • A mensagem é exibida com a data. Fica mais claro o exemplo, além do fato de que elas estão sendo registradas no “log”, para eventuais acessos futuros.

Melhor ficaria, se a saída fosse aperfeiçoada, como a versão 3 do teste:

<?php
Mensagem = "Teste da classe db, Versão 3";
$msg->Exibe();

$db_faleok1 = new BancodeDados();
$msg->Mensagem = "Instâncias abertas: " . BancodeDados::$idBancodeDados;
$msg->Exibe();
$msg->LogFaleOK();

$db_faleok2 = new BancodeDados();
$msg->Mensagem = "Instâncias abertas: " . BancodeDados::$idBancodeDados;
$msg->Exibe();
$msg->LogFaleOK();

?>

20120121 12:09:30 - Teste da classe db, Versão 3
20120121 12:09:30 - Instâncias abertas: 1
20120121 12:09:30 - Instâncias abertas: 2

O método direto exige algumas anotações sobre a Versão 3 do teste:

  • Retiramos o comentário // Teste x do início e deixamos somente na mensagem a ser exibida na tela. Evitamos duas alterações de versões.
  • A mensagem da versão só é exibida na tela. Não é registrada no “log”.
  • Já percebe-se que o método construtor executa, imediatamente, ao se definir uma instância da classe. Mas, não temos noção do momento no qual o método destrutor é executado. Geralmente é depois que o programa principal termina (no nosso caso, o testegeral.php), ou logo depois da execução de algumas instruções após a última instrução que atua sobre a instância de uma classe.

A fim de fixar bem a questão do destrutor, abaixo está a versão 2, da classe, na qual adicionamos comentários e alteramos o método __destruct incluindo dois comandos. O primeiro, subtraindo 1 da propriedade estática $idInstanciaDB, pois ela representa o número de instâncias. Destruir significa, também, não possuir nenhuma instância! Incluímos uma saída na tela, para imprimir o momento da destruição e somente mostramos os trechos importantes:

<?php

      .
      .
      .
class db extends mysqli {
    
    static $idBancodeDados = 0;
      .
      .
      .    
    public function __construct() {
        self::$idBancodeDados++;
    }
    
    public function __destruct() {
        --self::$idBancodeDados;
        echo '
Executou a destrutora as ' . date("Ymd H:i:s"); } } Mensagem = "Teste da classe db, Versão 4"; $msg->Exibe(); $db_faleok1 = new BancodeDados(); $msg->Mensagem = "Instâncias abertas: " . BancodeDados::$idBancodeDados; $msg->Exibe(); $msg->LogFaleOK(); $db_faleok2 = new BancodeDados(); $msg->Mensagem = "Instâncias abertas: " . BancodeDados::$idBancodeDados; $msg->Exibe(); $msg->LogFaleOK(); ?> 20120121 17:19:01 - Teste da classe db, Versão 4 20120121 17:19:01 - Instâncias abertas: 1 20120121 17:19:01 - Instâncias abertas: 2 Executou a destrutora as 20120121 17:19:01 Executou a destrutora as 20120121 17:19:01

Os comentários sobre o código acima:

  • Duas instâncias foram abertas, portanto, duas execuções de destrutores.
  • Os métodos destrutores foram executados em algum momento após o término do programa.

A versão final, completa e bem ilustrativa seria:

<?php

/**
 *  @author     JB 
 *  @version    2.0 (última revisão: Janeiro 18, 2012)
 *  @copyright  (c) 2005-2012 Julião Braga
 *  @license    No licence
 *  @package    Banco de dados
 *
 * 
 * Classe BandodeDados:
 * 
 */

class BancodeDados extends mysqli {
    
    static $idBancodeDados = 0;
    
    public $nome_da_base;
    
    /**
     * Construtor:
     * 
     * 
    */
    
    public function __construct() {
        self::$idBancodeDados++;        
    }
    
    public function __destruct() {
        --self::$idBancodeDados;    
    }
}

?>

Mensagem = "Teste da classe BancodeDados, Versão 4";
$msg->Exibe();

$db_faleok1 = new BancodeDados();
$db_faleok2 = new BancodeDados();

$msg->Mensagem = "1 Instâncias abertas: " . BancodeDados::$idBancodeDados;
$msg->Exibe();
$msg->LogFaleOK();

$db_faleok1 = NULL;

$msg->Mensagem = "2 Instâncias abertas: " . BancodeDados::$idBancodeDados;
$msg->Exibe();
$msg->LogFaleOK();

$db_faleok2 = NULL;

$msg->Mensagem = "3 Instâncias abertas: " . BancodeDados::$idBancodeDados;
$msg->Exibe();
$msg->LogFaleOK();
?>

20120122 14:20:25 - Teste da classe db, Versão 4
20120122 14:20:25 - 1 Instâncias abertas: 2
20120122 14:20:25 - 2 Instâncias abertas: 1
20120122 14:20:25 - 3 Instâncias abertas: 0

Eis as observações sobre o código acima:

  • A forma de executar o destrutor, para uma determinada instância da classe é: $nome_da_Instância->NULL;.
  • Executar ou não o destrutor é uma decisão do programador. Se o programador gosta de exercer o controle total sobre seu código, então ele mesmo destrói.

 

O próximo método

Uma questão aparece, imediatamente está relacionada com o velho dilema: “quem veio primeiro? O ovo ou a galinha? No nosso contexto:

  1. As informações sobre Bases de Dados remotas, geralmente são repassadas e há alguma dificuldade para alterar a senha original. Mas, o desejável, sob o ponto de vista da segurança é que a senha não seja conhecida nem mesmo pelo usuário da base. Em outras palavras, não se deseja ver a senha ou, na melhor das hipóteses, o menor número de pessoas deveriam ver a senha.
  2. Neste sentido, a senha pode ser complicada e deverá ser gerada automaticamente pela classe e alterada automaticamente pela classe, preferencialmente.
  3. Na mesma linha de raciocínio, as informações deveriam ser incluídas pela classe, devidamente criptografada, como é o desejo inicial.

Assim, o próximo método a ser criado é o insereDB, cujo objetivo é inserir na base as informações que serão passadas pelo usuário da classe. Eis o cabeçalho de tal método:

public function insereBD($nomeBD, $usuarioBD, $senhaBD, $hostBD, $portaBD, $descricaoBD, $email_criadorBD) {

// corpo do método
}

Os primeiros cinco parâmetros são autoexplicativos. O parâmetro $descricaoDB é uma descrição sucinta da base de dados e o parâmetro $email_criadorBD identifica o e-mail do “dono” da base, que será usado, para contato automático, em oportunidades sensíveis à segurança. O código abaixo é o refinamento preliminar, que antecederia o tratamento dos dados entrantes e a inclusão na tabela:

class BancodeDados extends mysqli {
    
    static $idBancodeDados = 0;
    static $BancodeDadosAbertos = array();
    
    private $_cripto;
    
    private $_caracteres;
    private $_maximo;
    private $_passwd;
    private $_nome; 
    private $_usuario;
    private $_senha;
    private $_host;
    private $_porta;
    private $_descricao;
    private $_email_criador;
    private $_senha_alternativa;
    private $_senha_alternativaBD;
    
    private $_bd;
    
    /**
     * Construtor:
     * 
     * 1. Verifica se o banco de dados já existe
     * 2. Se não existir cria, sem popular
     * 3. Se existir, abre
     * 4. {@usa: throw new DBConnectException($this->connect_error, $this->connect_errno);}
     *    para cobrir exceções
     * 
    */
    
    public function __construct() {
        self::$idBancodeDados++; 
                       
    }
    
    /**
        *   @author      JB 
        *   @version     1.0 (última revisão: Janeiro 18, 2012)
        *   @copyright   (c) 2005 - 2012 Julião Braga
        *   @license     No licence
        *   @package     funcoesgerais.phpn
        *   @nome        criaDB($nomeBD) 
        *   @funcao      Cria dados criptografados na tabela `basesdedados` da base faleok
        * 
        *   @Colunas:
        *       id_bd: INT
        *       nome_bd: VARCHAR
        *       usuario_bd: VARCHAR
        *       senha_bd: VARCHAR
        *       host_bd: VARCHAR
        *       porta_bd: VARCHAR
        *       descricao_bd: VARCHAR
        *       email_criador_bd: VARCHAR
        *       senha_alternativa: VARCHAR
        * 
    */
    public function insereBD($nomeBD, 
                             $usuarioBD, 
                             $senhaBD, 
                             $hostBD, 
                             $portaBD, 
                             $descricaoBD, 
                             $email_criadorBD) {
        
        $this->_cripto        = new cripto; 
        
        $this->_caracteres = 'abcdxywzABCDZYWZ0123456789@#*'; 

        $this->_maximo = strlen($this->_caracteres)-1;  
        $this->passwd = null; 
        mt_srand(make_seed()); 
        for($i=0; $i passwd .= $this->_caracteres{mt_rand(0, $this->_maximo)}; 
        }
        $this->_senha_alternativaBD = $this->passwd;
        
        $this->_nome          = $this->_cripto->encrypt($nomeBD); 
        $this->_usuario       = $this->_cripto->encrypt($usuarioBD);
        $this->_senha         = $this->_cripto->encrypt($senhaBD);
        //$this->_senha_alternativaBD = base_convert(mt_rand() , 10 , 16);
        $this->_host          = $this->_cripto->encrypt($hostBD);
        $this->_porta         = $this->_cripto->encrypt($portaBD);
        $this->_descricao     = $this->_cripto->encrypt($descricaoBD);
        $this->_email_criador = $this->_cripto->encrypt($email_criadorBD);
        $this->_senha_alternativa = $this->_cripto->encrypt($this->_senha_alternativaBD);
        
        // Tratamento dos dados
        
        echo "Aqui entra o código para imprimir o resultado apresentado na figura, logo abaixo";
            
        self::$BancodeDadosAbertos[self::$idBancodeDados] = $this->_cripto->decrypt($this->_nome);
        echo '
Indice do vetor de BancodeDadosAbertos: ' . self::$idBancodeDados . "...pre..."; print_r(self::$BancodeDadosAbertos); echo ".../pre..."; return true; } /** * * listaBDs() */ public function listaBDs() { return $bds; } public function __destruct() { --self::$idBancodeDados; //$this->_bd->close(); } } function make_seed() { list($usec, $sec) = explode(' ', microtime()); return (float) $sec + ((float) $usec * 100000); } <?php require_once ($_SERVER['DOCUMENT_ROOT'] . "faleok/includes/funcoesgerais.phpm"); $bd_faleok = new BancodeDados(); $nomeBD = "nomedoBD"; $usuarioBD = "usuarioautorizado"; $senhaBD = "teste"; $hostBD = "127.0.0.1"; $portaBD = "3306"; $descricaoBD = "BD de teste"; $email_criadorBD = 'usuario@exemplo.com.br'; echo '
Retorno do método; ' . $bd_faleok->insereBD($nomeBD, $usuarioBD, $senhaBD, $hostBD, $portaBD, $descricaoBD, $email_criadorBD); ?>

O resultado do programa acima pode ser visto na figura abaixo:


 

Os comentários são os seguintes:

  1. Uma outra propriedade estática foi incluída motivada pelo interesse em saber, para efeitos de gerenciamento e eficiência, quais as bases estão abertas em um determinado instante. É um “array” e sua atribuição é feita dentro do método insereBD:
    static $BancodeDadosAbertos = array();
    

    Já é possível antever um método listaDB, lembrado no códito, que informaria quais as bases abertas até o momento.

  2. Insistentemente, declaramos propriedades. Sempre que possível escondendo informações para outros componentes (encapsulamento), através do uso de private.
  3. A senha alternativa, isto é, aquela desconhecida de todos é gerada aleatoriamente, e com 15 caracteres, já que o ser humano não a manipula. Os algoritmos para isto estão disponíveis na Internet. Para aumentar a dificuldade, além dos 15 caracteres foi seguida a sugestão de usar um “alimentador” (‘make_seed’), para a função ‘mt_rand’, disponível no sítio do PHP. A função ‘make_seed’ está isolada no programa principal para, oportunamente, definir seu destino.

  1. Nenhum comentário ainda.
  1. No trackbacks yet.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

%d blogueiros gostam disto: