Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
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);
}
}
}como por exemplo ? :
public static function getInstance() {
if(!isset($_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}ou passar private static $db_connection; etc... ?
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
Alguns pontos a considerar:
- Uma conexão não deve ser estendida, ela deve ser apenas utilizada. Você pode utilizar [injeção de dependencia](http://en.wikipedia.org/wiki/Dependency_injection). Caso queira utilizar mais de uma conexão a SGBDs diferentes, [adapter](https://sourcemaking.com/design_patterns/adapter) ou [facade](https://sourcemaking.com/design_patterns/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](https://sourcemaking.com/design_patterns/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](http://php.net/manual/en/language.operators.errorcontrol.php). 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;
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 ?
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);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.
Olá Pessoal o que é PDO ?
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();
}
}
}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...
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:
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...
: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.