Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

TheNight

Está é uma boa técnica de conexão?

Recommended Posts

Bom guys, eu tinha feito uma conexão com MySQLi e então resolvi mudar.

 

Obs: não me venham falar de PDO, pq até agora não me familiarizei com PDO ainda...

class Connect extends mysqli {
    public $db_connection, $db_hostname, $db_username, $db_password, $db_database;
    
    public function __construct() {
        $this->db_hostname = DB_HOSTNAME;
        $this->db_username = DB_USERNAME;
        $this->db_password = DB_PASSWORD;
        $this->db_database = DB_DATABASE;
        $this->connectMe();
    }
    
    private function connectMe() {
        $this->db_connection = @$this->connect($this->db_hostname, $this->db_username, $this->db_password, $this->db_database);
        
        if($this->connect_error) {
            die("Falha na tentativa de se conectar com o servidor: " . $this->connect_error);
        }
    }
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Obs: não me venham falar de PDO, pq até agora não me familiarizei com PDO ainda...

:D

 

Passe estes dados de acesso dentro de uma instancia, ao invés do construtor.

 

Tendo um instancia da Classe de conexão, você evita conexões simultâneas dentro de outros objetos.

Compartilhar este post


Link para o post
Compartilhar em outros sites

como por exemplo ? :

 

public static function getInstance() {
if(!isset($_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}

???

 

ou passar private static $db_connection; etc... ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

De uma estudada e ve onde possa melhorar e otimizar os scripts abaixo, pois é bem antigo, mas lá pelo meados de 2008 e como fazíamos pra usar mysqli em Oo, hoje a maioria usa PDO, acredito que você ira utilizar mais a frente. :P

<?php

class DB {

    private static $db;
    private static $_config = null;
    private $_connection = null;

    private function __construct() {
        
    }

    public static function getInstance() {

        if (func_num_args() == 4) {
            self::$_config = func_get_args();
        } else {
            self::$_config[0] = defined("SERVER") ? SERVER : '';
            self::$_config[1] = defined("USER") ? USER : '';
            self::$_config[2] = defined("PASS") ? PASS : '';
            self::$_config[3] = defined("DB") ? DB : '';
        }

        if (!(self::$db instanceof DB)) {
            
			$class = __CLASS__;
			self::$db = new $class;
        }
        return self::$db;
    }

    protected function _connect() {
        if ($this->_connection) {
            return;
        }

        if (!extension_loaded('mysqli')) {
            throw new Exception('É necessario a extension Mysqli.');
        }

        if (is_array(self::$_config)) {
            $this->_connection = mysqli_init();

            if (!$this->_connection) {
                throw new Exception('mysqli_init failed');
            }

            $_isConnected = @mysqli_real_connect(
                            $this->_connection, self::$_config[0], self::$_config[1], self::$_config[2], self::$_config[3]
            );
            if ($_isConnected === false || mysqli_connect_errno()) {
                throw new Exception(mysqli_connect_error());
            }
        }
    }

    public function getConnection() {
        $this->_connect();
        return $this->_connection;
    }

    public function isConnected() {
        return ((bool) ($this->_connection instanceof mysqli));
    }

    public function closeConnection() {
        if ($this->isConnected()) {
            $this->_connection->close();
        }
        $this->_connection = null;
    }

    public function query($sql = '') {
        if ($sql != '') {
            $this->_connect();
            return $this->_connection->query($sql);
        }
    }

    public function prepare($sql = '') {
        if ($sql !== '') {
            $this->_connect();
            return $this->_connection->prepare($sql);
        }
    }

    public function fetchOne($sql = '') {
        if ($sql != '') {
            $this->_connect();
            $rs = $this->_connection->query($sql);
            $re = $rs->fetch_array();
            return $re[0];
        }
    }

    public function lastInsertId() {
        $mysqli = $this->_connection;
        return (string) $mysqli->insert_id;
    }

    public function __clone() {
        trigger_error('Clone is not allowed.', E_USER_ERROR);
    }

}

Depois é só estanciar a Conexão

 

$db = DB::getInstance();

//forçando a conexao

$db->getConnection();

Uso

$db->query('...')
//Fecha conexão com o banco
$db->closeConnection();


Pega o ID do insert

$db->lastInsertId();

Esta faz um count, mas existe forma mais simples

fetchOne

 

 

Com Construtor

<?php
    /*
     * Mysqli database class - only one connection
     */
    class Database{
        private $_connection;
        private static $_instance; //The single instance
        private $_host = 'localhost';
        private $_username = 'root';
        private $_password = '';
        private $_database = 'blogwebsite';

        public static function getInstance(){
           if(!self::$_instance){ // If no instance make one
                self::$_instance = new self();
            }
            return self::$_instance;
        }

        /*
         * Constructor
        */
        public function __construct(){
            $this->_connection = new mysqli($this->_host, $this->_username,  
            $this->_password, $this->_database);

             // Error handling
             if(mysqli_connect_error()){
             trigger_error("Failed to connect to MySQL: " .  
              mysqli_connect_errno(), E_USER_ERROR);
           }else{
               echo "You are connected to " . $this->_database;
           }
       }

        // Magic method clone is empty to prevent duplication of connection
        public function __clone(){ }

       // Get mysqli connection
       public function getConnection(){
           return $this->_connection;
        }
    }
?>

Bons estudos

Compartilhar este post


Link para o post
Compartilhar em outros sites

Alguns pontos a considerar:

 

- Uma conexão não deve ser estendida, ela deve ser apenas utilizada. Você pode utilizar injeção de dependencia. Caso queira utilizar mais de uma conexão a SGBDs diferentes, adapter ou facade pode ser útil;

- Injete, também, as propriedades (dados de conexão). Você não quer limitar seu sistema a uma só conexão;

- Perpetue a instância da forma correta através da sua aplicação. Seja por injeção de dependência ou Registry, mas evite singleton para conexões com Banco de Dados. Singleton possui sua utilidade sim, mas deve ser evitado ao máximo, pois normalmente é utilizado de forma errada;

- Não utilize supressão de erros. Se a conexão falhou, seu sistema não funcionará. Ao invés de suprimir o erro, trate o erro e avise ao usuário;

- O mesmo vale para o die. Ao invés, lance uma exception.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Me tire uma dúvida Gabriel, que o assunto OPP sempre me interessa, e estou aqui também para aprender, apesar que uso em meus sistemas injeção de dependência e Registry, alguns falam em posts "evite Singleton" e recomenda "Registry", este que tem em sua base o Singleton. Até ai tudo bem, você explanou e tirou minhas dúvidas tempo atrás aqui

Com PDO tem este exemplo e fica fácil a compreensão, o qual sempre recomendo, e quando lembro é claro!

 

Mas como seria utilização de Registry com mysqli ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

A utilização seria da mesma forma. Sendo o Registry um repositório de objetos, MySQLi permite a utilização orientada a objetos.

$registry = Registry::getInstance();
$mysqli = new mysqli(/** dados **/);
$registry->set('mysqli' , $mysqli);

Ou quando necessito de mais de uma conexão:

$registry = Registry::getInstance();

$conexao1 = new mysqli(/** dados **/);
$registry->set('mysqli-conexao1' , $conexao1);

$conexao2 = new mysqli(/** dados **/);
$registry->set('mysqli-conexao2' , $conexao2);

Isso depende da forma que seu sistema foi modelado. Entretanto, se, de alguma forma, não for utilizado uma conexão orientada a objetos, deve-se, então, encapsular a conexão em um objeto.

 

Como antigamente era feito com as mysql_*, mssql_* pg_* ou com o seu exemplo, onde a conexão mysqli foi encapsulada ao objeto DB.

 

Remove-se a restrição do singleton e utiliza-se normalmente:

$registry = Registry::getInstance();
$database = new Database();
$registry->set('database' , $database);

Compartilhar este post


Link para o post
Compartilhar em outros sites

Show!!!

 

Sanou minhas dúvidas, até porque com as novas versões do PHP, não é mais necessário $mysqli->close().

$thread = $mysqli->thread_id;
$mysqli->close();
$mysqli->kill($thread);

Para efetuar as limpezas, daqui pra frente não recomendarei mais Singleton com DB nas postagens! :thumbsup:

Valeu!! :worship:

Obrigado.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom, dei uma estudada mais profunda neste assunto, e cheguei a seguinte conclusão: Não preciso fazer o que eu fiz sendo que uma única class faria o mesmo ou até melhor!!! assim:

 

class Connect {


    // MySQLi object instance
    public $mysqli = null;


    // Class constructor override
    public function __construct() {
        $this->mysqli = @new mysqli(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);


        if ($this->mysqli->connect_error) {
            echo "Error MySQLi: " . $this->mysqli->connect_error;
            exit();
        }
    }
}

Gabriel, Williams, eu estou impaciente, estou tentando escolher entre MySQLi e PDO, porém não consigo me familiarizar de jeito maneira...

 

Vale lembrar que sou iniciante, e qualquer fonte sobre o assunto é bem vinda, sendo que eu li e relei o que vocês mandaram e eu entendi muito pouco :(

 

Haa! e também gostaria de saber como tratar estes erro, ouvi falar que se colocar um "@" resolve igual eu fiz ali mas o sistema fica vulnerável a invasões...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Então como foi mencionado, você fica engessado ao passar os dados de conexão por constantes de valor único, ou seja vai utilizar um único banco de dados, e não vários Bancos.

 

Seu caso:

$this->mysqli = @new mysqli(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);

O mais simples é passar estes dados via o método __construct, como foi dito pelo Gabriel, "Injete os dados"

 public function __construct($hostname, $username, $password, $database) {

No construtor do mysqli

$this->mysqli = new mysqli($this->hostname, $this->username, $this->password, $this->database);
class Connect {

    public function __construct() {
        $this->mysqli = @new mysqli(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
        if ($this->mysqli->connect_error) {
            echo "Error MySQLi: " . $this->mysqli->connect_error;
            exit();
        }
    }
}

 

E como já foi falado, evite supressão de erros e falhe elegantemente, use Exeções

Exemplo de captura do erro:

throw new Exception("Error MySQLi: " . $this->mysqli->connect_error);

A Classe inteira, ficaria assim

//Connect.php

<?php

class Connect {

    // MySQLi object instance
    private $mysqli;

    // Class constructor override
    public function __construct($hostname, $username, $password, $database) {
		
		$this->mysqli = new mysqli($hostname, $username, $password, $database);

		if ($this->mysqli->connect_errno) {
			
			throw new Exception("Error MySQLi: " . $this->mysqli->connect_error);
			
		}
		
		return $this->mysqli;
		
    }
	
}

Ou assim

<?php

class Connect {

    // MySQLi object instance
    private $mysqli;
    private $hostname;
    private $username;
    private $password;
    private $database;

    // Class constructor override
    public function __construct($hostname, $username, $password, $database) {
	
		$this->hostname = $hostname;
		$this->username = $username;
		$this->password = $password;
		$this->database = $database;
		
		$this->mysqli = new mysqli($this->hostname, $this->username, $this->password, $this->database);

		if ($this->mysqli->connect_errno) {
			
			throw new Exception("Error MySQLi: " . $this->mysqli->connect_error);
			
		}
		
		return $this->mysqli;
		
    }
	
}

Ai amigo,você pode encapsular quantas conexões quiser, ou seja, sua conexão fica ilimitada a qualquer banco do MySQL, mas restrito a somente e exclusivo SGBD "MySQL", diferente da PDO.

 

Veja um exemplo de como passar os dados de acesso, para o construtor da classe:

$connect1  = new Connect('localhost', 'root', '123456', 'banco1');

Para usar de uma forma mais simples os dados de conexão, passe por parâmetro através do objeto.

$class1 = new Data1();
$class1->insert($connect1);

No exemplo acima use normalmente as constantes

DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE

Mas a mágica e usar de diversas conexões e simultânea:

$connect1  = new Connect('localhost', 'root', '123456', 'test');	
$connect2  = new Connect('localhost', 'root', '123456', 'banco2');	
$connect3  = new Connect('other', 'root', '123456', 'banco');	
$connect4  = new Connect('216.58.222.3', 'root', '123456', 'banco');	
	
$class1 = new Data1();
$class1->insert($connect1);
	
$class2 = new Data2();
$class2->update($connect2);
	
$class3 = new Data3();
$class3->delete($connect3);
	
$class4 = new Data4();
$class4->seletc($connect4);

Voltando a classe de conexão, após lançar o erro na Exception

throw new Exception("Error MySQLi: " . $this->mysqli->connect_error);

Coloque os códigos dentro do bloco try/catch, caso tenha algum erro, será lançada uma exceção no bloco catch, dentro deste bloco, você manipula as informações retornadas das classes.

try {


} catch (Exception $e) {


}
<?php
ini_set('display_errors', FALSE);

include_once 'Connect.php';

try{
	
	$connect1  = new Connect('localhost', 'root', '123456', 'test');	
	$connect2  = new Connect('localhost', 'root', '123456', 'banco2');	
	$connect3  = new Connect('outro', 'root', '123456', 'banco');	
	$connect4  = new Connect('216.58.222.3', 'root', '123456', 'banco');	
	
	$class1 = new Data1();
	$class1->insert($connect1);
	
	$class2 = new Data2();
	$class2->update($connect2);
	
	$class3 = new Data3();
	$class3->delete($connect3);
	
	$class4 = new Data4();
	$class4->seletc($connect4);

	
	
} catch (Exception $e){

	echo "Um erro ocorreu.<br />";
	echo "Número da linha: ".$e->getLine()."<br />";
	echo "Nome Do Arquivo: ".$e->getFile()."<br />";
	echo "Descrição do erro: ".$e->getMessage();
	
}

Haa! e também gostaria de saber como tratar estes erro, ouvi falar que se colocar um "@" resolve igual eu fiz ali mas o sistema fica vulnerável a invasões...

 

Isso é jogar sujeira para debaixo do tapete. :assobiando:

Você pode esconder do usuário, casso esteja habilitado para mostrar os erros em tela.

ini_set('display_errors', FALSE);

Aqui algumas formas de criar logs de erros para saber oque esta ocorrendo em backgroud

 

 

Outra Dica é criar suas próprias classes de validação, estendendo a classe Exception, para tratar devidamente cada erro.

class FileException extends Exception {	
	// Exceptions para erros com o sistema de arquivos
}

class ValidateException extends Exception {
	
	// Exceptions para erros com a validação
}

class SQLException extends Exception {
	
	// Exceptions para erros com a conexão de banco de dados
}

exemplo utilizando suas próprias Exceptions

Na Connect

throw new SQLException("Error MySQLi: " . $this->mysqli->connect_error);

No bloco try/catch

try {
							
} catch (SqlException $e) {
							
} catch (ValidateException $e) {

}

//etc....

Você pode também utilizar as Exceptions nativas da biblioteca para padronizar seu código, até mesmo para facilitar futuras manutenções por outros desenvolvedores.

 

Saiba mais sobre cada uma delas aqui

 

 

Gabriel, Williams, eu estou impaciente, estou tentando escolher entre MySQLi e PDO, porém não consigo me familiarizar de jeito maneira...

Bom não sei se é seu caso, mas para quem vem de programação estrutural para OPP, sofre um um pouco para aprender no inicio, e não é da noite para o dia, por isso poucos se arriscam. B)

Ps.: Este cara fala que qualquer um aprende qualquer coisa em 20 horas, acredito que sim, mas com foco, ai vai embora.

 

Mas para que vai em frente, e encare ela, acaba vendo que os ganhos é muito maior que a dor. :)

 

E sobre MyQLI OO e PDO, não há muita diferença entre as formas de uso, e até mesmo os nomes das funções são bem parecidas.

Chega por aqui, fica para a próxima. :thumbsup:

Compartilhar este post


Link para o post
Compartilhar em outros sites

Opa, Williams Duarte, muito obrigado, acho que você consegui responder todas minhas dúvidas até este ponto, vou marcar sua resposta como resolvido, da próxima dúvida abro outro tópico, grato...

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.