Ir para conteúdo

Arquivado

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

Cabral Desenvolvedor

VO, DTO, Model, DAO

Recommended Posts

Boa observação... Eu NÃO RECOMENDO fazer isso.

 

Como eu faria se não quisesse mais utilizar MySQL? Se quiser utilizar PostgreSQL, ou Oracle, ou SQLite, ou qualquer outro SGBD???

Vou ter que ir lá dentro da classe e mexer nela...

Ok, para a maioria dos desenvolvedores PHP não é um grande problema, afinal, é só ir lá e alterar o instanciamento dentro do construtor.

 

Agora vamos pensar em C++ ou Java. Eles possuem há tempos o conceito de bibliotecas (arquivos *.a, *.so, *.dll no caso do C, *.jar no caso do Java), às quais você não tem acesso ao código-fonte, só à API. Você só chama as funções/métodos sem ter ideia nenhuma de como ela é internamente implementada.

O PHP possui algo semelhante, os pacotes PHAR.

 

Imagine que você está desenvolvendo algo que será utilizado por terceiros no futuro, e você faz:

class Table
private $driver;
public function __construct() {
   	$this->driver = new Driver(new MySQLi());
}
}

 

Aí, depois de testar e ver que funciona que é uma beleza, você joga tudo isso num PHAR pra se certificar de que ninguém vai mexer e correr o risco de ferrar com tudo o que você fez... Distribui esse código, seja emprestando para um amigo, ou vendendo... A pessoa que utiliza esse pacote também utiliza MySQL, funciona tudo perfeito até que um dia ela precisa utilizar PostgreSQL. Ela vai revirar a API que você forneceu junto de cima abaixo e não vai encontrar nada sobre como alterar a API de acesso ao SGBD...

 

Esse problema é chamado de Dependência Oculta. Seu código tem uma dependência que só é possível encontrar olhando a estrutura interna.

 

Aí você pensa:

 

 

Você mesmo pode um dia precisar alterar o SGBD e para tal, terá que mexer numa classe que já está pronta. Isso é péssimo.

 

O conceito bem simples que eu utilizo no exemplo chama-se Injeção de Dependências. Com isso, eu torno todas as dependências de uma determinada classe explícitas, lhes passando as instâncias dos objetos que ela depende no construtor (ou em algum método).

 

Dessa forma, eu posso fazer assim:

$tableMy = new Table('users', new Driver(new MySQLi(...))));
$tablePg = new Table('clients', new Driver(new PgSQL()))); // fictício, só existe API procedural para PostgreSQL no PHP, você teria que criar uma OO, o que não é muito difícil

 

Por que raios eu teria dados em 2 SGBDs? Vai saber... Mas e se um dia tiver? Vai ficar se descabelando? Não é melhor prevenir do que remediar?

 

Quer usar Singleton???

$table = new Table('users', new Driver(API_do_meu_bd()::getInstance()));

Resolvido...

 

Eu uso a seguinte classe Singleton para conexão com o banco de dados Conexao.class.php:

<?php
/**
 * Classe para conexão com banco de dados utilizando PDO
 * Design Pattern Singleton
 * Chaset UTF-8
 * @author Douglas Cabral
 * @date 5 de março de 2012 14:21
 * @version 1.0.0
 * @final
 */
final class Conexao {

	private static $conexao = null; //Instância da conexão

	private function __construct(){} //Evita que a classe seja instanciada

	private function __clone(){} //Evita que a classe seja clonada

	/**
	 * Método para pegar a conexão existente
	 * Se o mesmo não existir, instancia uma nova conexão
	 * @access public
	 * @return PDO
	 * @static
	 */
	public static function getConexao(){
		if(!self::$conexao){
			//Realiza a conexão com o banco de dados
			self::$conexao = new PDO("mysql:host=localhost;dbname=teste", "root", "");

			//Define como serão exibidos os erros do PDO
			self::$conexao->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

			//Parte responsável por trazer os dados com o charset em UTF-8
			self::$conexao->exec("SET NAMES 'utf8'");
			self::$conexao->exec("SET character_set_connection=utf8");
			self::$conexao->exec("SET character_set_client=utf8");
			self::$conexao->exec("SET character_set_results=utf8");
		}
		return self::$conexao;
	}
}
?>

 

Como bastaria eu alterar os dados de conexão dentro do construtor desta classe, não seria mais fácil eu fazer dentro das classes que necessitarem de conexão com o banco de dados o seguinte comando:

$conexao = Conexao::getConexao();

 

Pois se alterasse o banco de dados para Postgree eu teria no seu exemplo em todas as classes ficar mudando de:

new Driver(new MySQL())

para :

new Driver(new Postgree())

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom, já que você utiliza PDO, poderia adaptar a classe Driver para trabalhar com PDO...

Aí você faria o seguinte:

$driver = new Driver(new PDO($dsn));

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom, já que você utiliza PDO, poderia adaptar a classe Driver para trabalhar com PDO...

Aí você faria o seguinte:

$driver = new Driver(new PDO($dsn));

 

Já que eu utilizo o PDO, acredito que não necessitaria eu adaptar a classe Driver e sim usar essa minha classe como se fosse o Driver.

 

Aí se eu fosse criar um TDG, eu criaria seu construtor da seguinte forma:

public function __construct(PDO $pdo){
//Implementação aqui
}

 

Aí na hora de instanciar usaria:

$table = new Table(Conexao::getConexao());

 

Se mudasse de tipo de banco de dados, é só mudar dentro de Conexao o DSN para o novo banco certo?

 

Só uma pergunta, essa tal de Injeção de Depedências, é deixar explicito em forma de parâmetros, as classes que a classe que recebe esses parâmetros irá utilizar?

Compartilhar este post


Link para o post
Compartilhar em outros sites
Se mudasse de tipo de banco de dados, é só mudar dentro de Conexao o DSN para o novo banco certo?

Se você for usar só SGBDs relacionais, beleza... PDO se adapta a quase todos... Pode fazer dessa maneira...

 

Só uma pergunta, essa tal de Injeção de Depedências, é deixar explicito em forma de parâmetros, as classes que a classe que recebe esses parâmetros irá utilizar?

Sim... exato...

Uma coisa que muitos confundem: não precisa setar todos os parâmetros direto no construtor, você pode ir injetando as dependências conforme precisar.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim... exato...

Uma coisa que muitos confundem: não precisa setar todos os parâmetros direto no construtor, você pode ir injetando as dependências conforme precisar.

 

E se ao invés de passar pelos vários parâmetros os objetos de várias classes diferentes, como banco de dados, etc, passasse um objeto Regitry?

 

No cado da injeção de dependências, ao instanciar uma model teria também que nela ficar passando o Driver, o TDG e o RDG na qual ela vai manipular?

Compartilhar este post


Link para o post
Compartilhar em outros sites

E se ao invés de passar pelos vários parâmetros os objetos de várias classes diferentes, como banco de dados, etc, passasse um objeto Regitry?

Olha, é melhor do que dependência explícita, mas ainda tem um certo acoplamento, pois cada classe precisa conhecer a oo Registry (pelo menos, sua interface)...

O conceito de injeção de dependências é que você só fornece para a classe exatamente o que ela precisa, nada a menos, nada a mais...

 

O que eu faço é o seguinte:

Tenho uma propriedade estática na classe Table, por exemplo, que armazena um objeto Driver e que eu seto no bootstrap.

Nisso, se eu não passar um objeto Driver ao instanciar Table, ele utiliza esse Driver padrão...

 

No cado da injeção de dependências, ao instanciar uma model teria também que nela ficar passando o Driver, o TDG e o RDG na qual ela vai manipular?

Olha, sinceramente, é impossível manter o model desacoplado do restante da aplicação, então injeção de dependências aqui não é bem aplicado...

Agora sim você é livre pra criar esses objetos lá dentro... se não, iria criá-los onde? No controller??? Não é responsabilidade dele...

 

Talvez dê até pra bolar uma estrutura que desacople um pouco, mas eu nunca tentei...

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.