Ir para conteúdo

Arquivado

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

Loid

Conexao ao Banco de Dados.

Recommended Posts

Olá, pessoal tudo joia.

 

Nesta classe tentei me focar no objetivo que é apenas conectar ao banco de dados e caso falhe retorne um erro, mas um erro tratado onde o usuário final não veria os avisos gerados pelo mysql.

 

lib.class.php ( library que contém as variaveis constantes do sistema);

ConexaoBanco ( Class que possui um metodo para CriarConexao, FecharConexao e ErroMysql);

 

//lib.class.php
<?php
define(SERVIDOR,'servidor');
define(USUARIO,'usuario');
define(SENHA,'senha');
define(DB_NOME,'banco_de_dados');

//erro_lib_mysql.php
....

$this->erroMySQL[2000] = "Erro desconhecido no MySQL!";

$this->erroMySQL[2003] = "Não é possível conectar ao servidor Host!";

$this->erroMySQL[2005] = "Servidor Host MySQL desconhecido!";

...
//lista os principais erros de acordo com o código gerado.

//ConexaoBanco.class.php

<?php 

class ConexaBanco  {
public $erroMySQL = array();
public $conexao;
public $variaveis_conexao = array();
public $include_arquivo;

function __construct(){
 
 require_once ('erro_lib_mysql.php');


}


 public function CriaConexao ($variaveis_conexao = NULL){
	
	$this->include_arquivo = ($variaveis_conexao == NULL) ? require_once('lib.class.php') : $c = explode(',',$variaveis_conexao);
	$this->servidor	= ($variaveis_conexao == NULL) ?  SERVIDOR :  $c['0'];
	$this->usuario 	= ($variaveis_conexao == NULL) ?  USUARIO  :  $c['1'];
	$this->senha 	= ($variaveis_conexao == NULL) ?  SENHA	:  $c['2'];
	$this->db_nome	= ($variaveis_conexao == NULL) ?  DB_NOME  :  $c['3'];
  
	
	@$this->conexao = new mysqli($this->servidor,$this->usuario,$this->senha,$this->db_nome);
	if(mysqli_connect_errno()){
	echo($this->ErroMysql());
	}else{
	return $this->conexao;	
	}
 
}


public function FechaConexao(){
return (@mysqli_close($this->conexao));
}


 public function LinkConexao(){
	if($this->conexao){
	return ($this->conexao);
	}else{
	return ($this->ErroMysql());
	}
}

 public function ErroMysql(){
	date_default_timezone_set("America/Sao_Paulo");
	$this->erroCodigo_MySQL = mysqli_connect_errno();
	if(array_key_exists($this->erroCodigo_MySQL, $this->erroMySQL)){
	$erro = "( ".date("d/m/Y H:i:s", time())." ) - [ ".mysqli_connect_errno()." ] ".$this->erroMySQL[$this->erroCodigo_MySQL].' na linha '. __LINE__ . ' no arquivo '.__FILE__."\n\n";
	error_log($erro,3,"erros.log");
	}else{
	$erro = "( ".date("d/m/Y H:i:s", time())." ) - [ ".mysqli_connect_errno()." ] " .$this->erroMySQL[$this->erroCodigo_MySQL].' na linha '. __LINE__ . ' no arquivo '.__FILE__."\n\n";
	error_log($erro,3,"erros.log");
 
   }
   return $this->erroMySQL[$this->erroCodigo_MySQL];

}
 

}

$t = new ConexaBanco;
$t->CriaConexao();
$t->FechaConexao();

Bom, esta class como fosses percebem verifica se há uma requisição ao um novo servidor com a variavel '$variaveis_de_conexao', caso queira realizar uma nova conexao, que não seja a padrão estabelecida na 'lib.class.php' bata instanciar na seguinte maneira.

 

$t->CriaConexao('servidor,usuario,senha,banco_de_dados');

//a class é responsavel por desmontar o array e estabelecer a conexao.
E e o metodo ErroMysql(); é responsavel por gerar os logs de erros salvando no arquivo 'erros.log'.

 

Bom suprimir avisos de erros e fiz este tratamento de erros, li que estes não são vias atimizadas para se trabalhar, se não quais são as mais otimizadas?

Bom oque vocês acham desta class?

 

Melhorou?

 

Grato, Jefferson.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom...é interessante você dar uma estudada em orientação a objetos,e uma lida sobre Design Patterns.

Acho que a DP singleton ou a DP factory teriam uma boa aplicação no seu programa.

Jogaria exceções em caso de erro para uma maior flexibilidade no tratamento dos mesmos (PDOs fazem isso em caso de erro).

Eu mudaria também o modo de declarar os parametros da conexão,os mesmos e os atributos da classe.

Depois de ler o sugerido,é interessante refazer seu código.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Eu mudaria também o modo de declarar os parametros da conexão,os mesmos e os atributos da classe.--

 

Teria com dar ume exemplo?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Colocaria uma variavel para cada parametro e um atributo que recebesse os mesmos (você chamou atributos não declarados como [ $this->db_nome ]).

Colocaria também métodos setters para cada atributo.

E não tinha visto...vi agora...você não seguiu os conceitos de encapsulamento.

Só o que falei agora não melhora muito não...sugiro que leia o que te falei e tente de novo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sei que você ta aprendendo e quer fazer do jeito certo, mas quando puder recomendo você extender a classe mysqli em vez de criar uma outra e usando ela dentro, extendendo a classe mysqli você tera um leque maior de opções e aproveitamento da classe.

 

e tente manter o padrao de conexao , por exemplo nao se passa 1 parametro, em todas as linguagens se passa uma conection string com varios parametros

 

dai para pegar os parametros você pode usar func_num_args(), func_get_args()

 

e defina as constantes sempre delimitadas por aspas define("SERVIDOR", 'servidor');

 

do jeito que você fez da erro, caso você nao percebeu é porque você ta trabalhando com display_errors = off ou error_reporting(0), corrija isso

 

montei rapido só um esboço de como seria uma classe de conexao extendendo a mysqli reaproveitando a propria classe pronta do PHP sem perder os metodos que ja existe da classe mysqli, e com uns metodos basicos e usando exceptions para melhor tratamento de erros é só pra você começar entender e dar continuidade melhorando a classe.

 

class DB extends Mysqli
{

public function __construct($host = "", $username = "", $passwd = "", $dbname = "")
{
	if(func_num_args() == 0){
		parent::__construct(SERVIDOR, USUARIO, SENHA, DB_NOME);
	} else {
		$args = func_get_args();
		eval("parent::__construct(" . join(',', array_map(array($this, "add_single_quotes"), $args)) . ");");
	}

	if (mysqli_connect_errno()) {
	   throw new Exception("Connect exception:\n".mysqli_connect_error());
	}
}

function add_single_quotes($arg)
{
	return "'" . addcslashes($arg, "'\\") . "'";
} 

function query($query)
{
	$result = parent::query($query);
	if(mysqli_error($this)){
		throw new exception(mysqli_error($this), mysqli_errno($this));
	}
	return $result;
}
}

 

$DB = new DB("localhost", "root", "root", "test");//passo os parametros para conectar no banco que eu quero

 

ou

 

$DB = new DB();// uso a conexao padrao ja pre configurada.

 

e como ja falaram aprenda singleton, e outros metodos, mas nao precisa ser direto, esta sendo sua primeira classe e nao se mate, tente faze-la funcionar depois você vai aprendendo e melhorando ela.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Opa ótimo exemplo fabyo!

Fica legal também extender Exception de forma 'a criar uma exceção menos genérica e mais personalizada' (PDOs fazem isso...aksoapsas).

Compartilhar este post


Link para o post
Compartilhar em outros sites

Esta certo, vou procurar fazer isso, extender a própia class mysqli, e tentar trabalhar com outros exemplos para ver se compreendo.

 

Obrigado pela dica, vou ler sobre estes padrões e refazer esta class.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Fabyo, estou trabalhando em cima deste exemplo que você passou, teria como você explicar esta linha:

 

eval("parent::__construct(" . join(',', array_map(array($this, "add_single_quotes"), $args)) . ");");

O resto esta tranquilo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Vou explicar pra você por partes:

array_map(array($this, "add_single_quotes"), $args)

Vai aplicar a função add_single_quotes em cada elemento do array args e vai retornar um array com os elementos de args modificados pela função(parecido com array_walk,este dando um retorno).O primeiro parametro do array_map,é uma função,mas como estamos trabalhando com objetos,declaramos um array com $this e o nome da função para se ter acesso a mesma.

 

join(',', array_map(array($this, "add_single_quotes"), $args))

Join é sinonimo de implode,vai dar um implode no array retornado pela função array map.

 

"parent::__construct(" . join(',', array_map(array($this, "add_single_quotes"), $args)) . ");"

É uma string concatenada com o resultado do join no array retornado pela função array_map.

 

eval("parent::__construct(" . join(',', array_map(array($this, "add_single_quotes"), $args)) . ");");

Tal string é executada.E tem como resultado uma chamada ao construtor da mysqli com os paramêtros alterados (single quote adicionado).

 

É o mesmo que:

public function __construct($host = "", $username = "", $passwd = "", $dbname = "")
	{
		if(func_num_args() == 0){
			parent::__construct(SERVIDOR, USUARIO, SENHA, DB_NOME);
		} else {
			$this->add_single_quotes($host);
			$this->add_single_quotes($username);
			$this->add_single_quotes($passwd);
			$this->add_single_quotes($dbname);
			parent::__construct($host, $username, $passwd, $dbname);
		}
		
		if (mysqli_connect_errno()) {
		   throw new Exception("Connect exception:\n".mysqli_connect_error());
		}
	}
	
	function add_single_quotes(&$arg)
	{
		$arg = "'" . addcslashes($arg, "'\\") . "'";
	}

Ou ainda:

public function __construct($host = "", $username = "", $passwd = "", $dbname = "")
	{
		if(func_num_args() == 0){
			parent::__construct(SERVIDOR, USUARIO, SENHA, DB_NOME);
		} else {
			$host = $this->add_single_quotes($host);
			$username = $this->add_single_quotes($username);
			$passwd = $this->add_single_quotes($passwd);
			$dbname = $this->add_single_quotes($dbname);
			parent::__construct($host, $username, $passwd, $dbname);
		}
		
		if (mysqli_connect_errno()) {
		   throw new Exception("Connect exception:\n".mysqli_connect_error());
		}
	}
	
	function add_single_quotes($arg)
	{
		return "'" . addcslashes($arg, "'\\") . "'";
	}

Só que de forma mais prática.

Abraço e espero que tenha entendido!

Compartilhar este post


Link para o post
Compartilhar em outros sites

só pra esclarecer mais caso alguem que leia nao entenda, a função eval executa uma string como se fosse um comando PHP

 

por isso passando uma string para eval() ele ia executar como se fosse a propria linha do script php

 

se eu fizesse isso:

 

parent::__construct(join(',', array_map(array($this, "add_single_quotes"), $args)));

 

nao iria funcionar porque o resultado do join seria uma string com virgulas assim:

 

("servidor", "usuario", "senha", "banco")

 

mas para o parent::__construct(), seria apenas 1 parametros ele nao iria interpretar as virgulas como se fosse parametros

 

só com a função eval isso seria possivel.

Compartilhar este post


Link para o post
Compartilhar em outros sites

muito bom esse exemplo Fabyo..

 

mas só um probleminha que eu tive aki..

e já tive outras vezes..

 

por exemplo..

 

se vou fazer duas consultas no banco..

as vezes a segunda consulta não funciona..

a conexão com o mysql eh perdida..

 

será q não seria melhor fechar a conexão a cada consulta?

 

eu utilizei uma classe q você criou a muito tempo atrás..

e ela abria e fechava a conexão em cada consulta..e funcionava muito bem..sem problemas..

apesar de parecer ilógico..abrir e fechar a conexão a cada consulta.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Entao primeiro esse exemplo que passei é só o começo, claro que com ele terminado nao tera esses problemas

 

e outra coisa claro que é logico, só abra a conexao quando for precisar dela, e fechar depois que nao precisar mais

 

o php por traz sempre fecha a conexao quando o script é encerrado ou quando o navegador é fechado, mas sempre é bom ter essas praticas

 

claro que se você ta num mesmo script e precisa fazer varias consultas você ira usar a mesma conexao, só feche quando nao precisar mais dela.

 

mas todo mundo lembra quando o orkut começou e o inumeros problemas que ele tinha de conexao, isso tudo foi um erro de script

 

uma coisa é fazer um sistema pra 1 usuario outro para milhoes de usuarios

Compartilhar este post


Link para o post
Compartilhar em outros sites

entendi..

 

mas o q você recomenda fazer então?

 

eu to fazendo testes locais aki no windows mesmo..e tah dand oesse problema..

provavelmente no server de produção tbm..pois como disse já tive esse problema antes..

 

eu fiz mais ou menos assim..

 

método contrutor da classe eu instancio a classe de connexão q conecta no banco..

 

e no método destrutor eu chamo o método para fechar a conexão..

então qdo não preciso mais do objeto, do um unset e boa..a conexão é fechada..

soh que esse problema acontece e eu chamo os métodos, bem próximos.. chamo um..e umas 4 linhas abaixo..chamo o outro..

o php fecha a conexão nesse pequeno intervalo (de código)

 

o que você me sugere?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Pessoal falando em Singleton, estava lendo parece que o php não suporta o 'Conceito de Aplicação', e que este padrão não resolveria bem a questão, bom pelo fato eu discordo ate mesmo pelos exemplos que vi, parece que realmente permite que a instancia, quando o script é requisitado, permanecendo com o objeto atual.

 

Bom, oque não conseguir achar foi sobre esse 'Conceito de Aplicação', fiquei pensando se seria levando em consideração o acesso de multiplos usuários, enfim não sei, tem como vocês comentarem sobre isso?

Compartilhar este post


Link para o post
Compartilhar em outros sites

resumidamente o que eu sei é que só vai existir uma instância do objeto na memória...

e pelo q eu uso aqui..

funciona sem problemas sim.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim, aqui também deu certo, porém fiquei com esta pulga atrás da orelha em relação a este 'Conceito de Aplicação';

Compartilhar este post


Link para o post
Compartilhar em outros sites

Lucas Rena, sobre sua duvida, de abrir a conexao e fechar usando construct e destruct, e depois aquele problema que você sitou

 

só pra você entender os metodos padroes que ja existem por ai como o caso do mysqli ele abre a conexao logo no construct porque é uma classe de manipulação de dados, e nao que por isso você seja obrigado a trabalhar assim, você pode criar suas classes e chamar ou estender da conexao e assim usar só na hora que precisa.

 

só uma observação o Zend Framework tem um controle excelente de conexao, mesmo que você chame a classe para abrir a conexao ele só vai abrir quando realmente precisar

Compartilhar este post


Link para o post
Compartilhar em outros sites

Fabyo..

 

estou de acordo com você...

não preciso abrir a conexão em toda a classe no método construtor..

 

é q coincidentemente eu sempre uso quase de "imediato" após instanciar o objeto algum método q realiza alguma query...

 

e muita boa sua observação sobre o Zend Framework..

 

eu estou estudando o Zend e estou achando demais...

muito bom mesmo...

principalmente segurança, organização e a questão de banco de dados.

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.