Ir para conteúdo

POWERED BY:

Arquivado

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

thiagohneves

Classe para conexão adodb e singleton

Recommended Posts

Olá galera,

 

estou criando umas classes pra um estudo mais apronfundado em orientação a objetos e gostaria da opnião de vocês para que possa melhorar se possível.

 

Classe Singleton

 

<?php

/**
 * Created 13/08/2009
 *
 * Classe para utilizar o design patter singleton
 * @author Thiago Neves <thiagohneves@gmail.com>
 * @version 1.0
 */

class Singleton {

    /**
     * Guarda as instâncias das classes
     * @access protected
     * @var string
     */
    private static $instance = array();

    /**
     * Metodo contrutor protected para previnir a criacao direta do objeto
     * @access protected
     */
    private function __construct() { }

    /**
     * Função que cria/retorna uma instância da classe
     * @final
     * @static
     * @access public
     * @return object
     */
    final public static function getInstance() {
        //Pega o nome da classe que chamou o método static - PHP 5.3
        $class = get_called_class();

        if(!isset(self::$instance[$class])) {
            self::$instance[$class] = new $class;
        }

        return self::$instance[$class];
    }

    /**
     * Função que destroi a instância da classe
     * @final
     * @access public
     */
    final public function destroyInstance() {
        unset(self::$instance[get_class($this)]);
    }

}

?>

Classe Connection utilizando a classe adodb

 

<?php
/**
 * Created 13/08/2009
 *
 * Classe para gerenciar banco de dados utilizando a classe adodb e
 * design pattern singleton
 *
 * @author Thiago Neves <thiagohneves@email.com.br>
 * @version 1.0.0
 */

//Inclui a classe adodb
require_once("adodb/adodb.inc.php");

class Connection extends Singleton {

    private $connection = null;

    //Atributos para conexao
    private $type       = "MySql";
    private $host       = "localhost";
    private $user       = "root";
    private $pass       = "root";
    private $database   = "estudo";

    /**
     * Metodo contrutor protected para previnir a criacao direta do objeto
     * @access protected
     */
    protected function __construct() {
        $this->connect();
    }

    /**
     *  Métodos que faz a conexão com o banco de dados
     *  @access public
     */
    public function connect() {
        $this->connection = NewADOConnection($this->type);
        $this->connection->Connect($this->host, $this->user, $this->pass, $this->database);

        $this->connection->SetFetchMode(ADODB_FETCH_ASSOC);

        $this->connection->EXECUTE("SET NAMES 'UTF8'");
    }

    /**
     * Método que fecha a conexão com o banco de dados
     * @access public
     * @return boolean
     */
    public function desconect() {
        return $this->connection->close();
    }

    /**
     * Método que habilita/desabilita o debug
     * @access public
     * @param <boolean> $value
     */
    public function setDebug($value) {
        $this->connection->debug = $value;
    }

    /**
     * Método que realiza a pesquisa no banco de dados
     * @param <string> $sql
     * @return <array> $res
     */
    public function query($sql) {
        $res = $this->connection->GetAll($sql);

        if($res) {
            return $res;
        }else {
            echo $this->connection->ErrorMsg();
        }
    }

    /**
     * Método que trata a string contra sql injection
     * @param <string> $string
     * @return <string>
     */
    public function sqlInjection($string) {
        //Remove palavras que contenham sintaxe SQL
        $string = preg_replace("/(from|select|insert|delete|where|drop table|show tables|#|\*|--|\\\\)/","",$string);

        //Escapa uma string para usar em uma consulta MySQL
        $string = mysql_escape_string($string);

        //Elimina espaços vazio no inicio e no fim da string
        $string = trim($string);

        //Remove tags html e php
        $string = strip_tags($string);
        
        return $string;
    }

    /**
     * Método magico que fecha a conexão assim que o objeto for destruido
     */
    public function  __destruct() {
        $this->desconect();
    }

}

?>

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá Thiago,

 

Muito interessante a sua Classe, porém não entendi uma coisa. Por que deixar os dois métodos construtores em modo privado se na Classe Connection você adcionou a chamada ao método de conexão ? Você está trabalhando como nessa Classe ? Dando new na Classe pai ou na Classe filho ? Se puder, deixe um explo de utilização da mesma. Estou trabalhando em uma Classe de Banco de Dados mista (MSSQL e MySQL) e acho que posso tirar algumas idéias da sua. Assim que estiver concluída, postarei aqui.

 

Obs.: Na preg_replace do método sqlInjection, adcione o comando 'truncate', que é utilizado para truncar a tabela do banco.

 

Abraços.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá youngrp,

 

os contrutores estão privados para impedir a instanciação direta da classe, pois utilizando o design patter singleton a ideia é que tenha somente uma instância da classe. Resolvi utilizar na classe para conexão para impedir várias conexões simultaneas ao banco.

 

sobre a utilização, o método getInstance() na class singleton é static você utiliza assim:

 

<?php
 $Con = Connection::getInstance();

 $sql = "SELECT * FROM usuario";
 $res = $Con->query($sql);
?>

o método getInstance() vai verificar se ja existe uma instancia para a classe, caso exista ele retorna a mesma instância senão ele cria uma. Qualquer classe que extender a singleton vai funcionar da mesma forma.

 

Veja só como cria somente uma instância da classe:

 

<?php
 $Con = Connection::getInstance();

 $sql = "SELECT * FROM usuario";
 $res = $Con->query($sql);
 
 $Con2 = Connnection::getInstance();
 
 if($Con == $Con2){
    echo "São iguais...";
 }else{
    echo "Não são iguais";
 }
?>

Sobre a sua classe para conexão mista...pode-se usar a adodb que trabalha junto com essa minha classe e so mudar o valor do $type na classe conexão para o banco que deseja usar

Compartilhar este post


Link para o post
Compartilhar em outros sites

os contrutores estão privados para impedir a instanciação direta da classe, pois utilizando o design patter singleton a ideia é que tenha somente uma instância da classe.

 

Bom, nesse caso, vou apenas passar um link, heheh (depois comentamos o resto) ;)

 

http://br.php.net/manual/en/language.oop5.abstract.php

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá João Batista Neto,

 

conheço os métodos e classes abstratos, acontece que utilizando o singleton não funciona classe abstrata porque é criada uma instância da classe que herda a singleton veja este trecho do método getInstance() da classe singleton:

 

if(!isset(self::$instance[$class])) {
   self::$instance[$class] = new $class;
}

caso não haja uma instância é criada uma...

 

os contrutores são privados para impedir a instânciação direta da classe ex:

 

<?php
   $con = new Connection();
?>

assim obrigando chamar Connection::getInstance()

Compartilhar este post


Link para o post
Compartilhar em outros sites

os contrutores são privados para impedir a instânciação direta da classe ex:

 

Certo, olha o seguinte:

 

<?php
abstract class Singleton {
    static private $storage = array();

    final public function __construct(){
        $class = get_class( $this );

        if ( isset( self::$storage[ $class ] ) && ( self::$storage[ $class ] ) ){
            throw new LogicException( "There can be only one. " );
        } else {
            self::$storage[ $class ] = true;
        }
    }

    final public function __destruct(){
        $class = get_class( $this );

        unset( self::$storage[ $class ] );
    }

}

class Highlander extends Singleton {
    protected $name;

    public function setName( $name ){
        $this->name = $name;
    }

    public function getName(){
        return( $this->name );
    }
}

try {
    $teste1 = new Highlander();
    $teste1->setName( "Connor MacLeod" );

    printf( "%s\n" , $teste1->getName() );

    $teste2 = new Highlander();
    $teste2->setName( "Kurgan" );

    printf( "%s\n" , $teste2->getName() );
} catch ( LogicException $e ){
    echo $e->getMessage();
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Certo...achei interessante como usou. Na sua resposta anterior tinha pensado que tinha se referido a classe Connection.

 

Para melhorar vou colocar a classe singleton como abstract e tirar o método contrutor, mais o método getInstance ainda deve ficar pois eu retorno a instância em vez de definir um erro caso tente criar uma outra instancia da classe (a não ser que tenha outra forma de fazer isso, que no caso eu desconheço).

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá Thiago,

 

Como prometi segue a minha Classe para MSSQL e MySQL. Não vejo aonde o Singleton pode se enquadrar nela, pois eu chamo pela Classe pai e não pelas Classes filho. Logo abaixo, colocarei um exemplo de como a uso também:

 

class.inc.php:

<?php
class dbClass {
	private	$to_child;
	
	protected function error($err_type) {
		switch ($err_type) {
			case 1 : die('Erro ao conectar no Servidor SQL !');
			case 2 : die('Erro ao selecionar o Banco de Dados !');
			case 3 : die('Tipo de Banco de Dados não suportado !');
			case 4 : die('Classe de Banco de Dados não incializada !');
			default : die('Erro desconhecido !');
		}
	}
	
	public function setdb($db_type) {
		switch ($db_type) {
			case 'mssql' :
				$this->to_child = new dbClassMssql();
				$this->to_child->connect();
				break;
			case 'mysql' :
				$this->to_child = new dbClassMysql();
				$this->to_child->connect();
				break;
			default :
				$this->error(3);
		}
	}
	
	public function query($query) {
		if ($this->to_child == NULL) $this->error(4);
		else return $this->to_child->query($query);
	}
	
	public function result($resource, $fetch = NULL) {
		if ($this->to_child == NULL) $this->error(4);
		else return $this->to_child->result($resource, $fetch);
	}
	
	public function dataseek($resource, $row) {
		if ($this->to_child == NULL) $this->error(4);
		else return $this->to_child->dataseek($resource, $row);
	}
	
	public function freeresult($resource) {
		if ($this->to_child == NULL) $this->error(4);
		else return $this->to_child->freeresult($resource);
	}
	
	public function close() {
		if ($this->to_child == NULL) $this->error(4);
		else return $this->to_child->close();
	}
}

class dbClassMssql extends dbClass {
	private	$db_link;
	
	public function connect() {
		if (!$this->db_link = @mssql_connect($GLOBALS['mssql_servidor'], $GLOBALS['mssql_usuario'], $GLOBALS['mssql_senha'])) parent::error(1);
		if (!@mssql_select_db($GLOBALS['mssql_banco'], $this->db_link)) parent::error(2);
	}
	
	public function query($query) {
		return mssql_query($query, $this->db_link);
	}
	
	public function result($resource, $fetch = NULL) {
		switch ($fetch) {
			case 'object' :
				return mssql_fetch_object($resource);
				break;
			case 'array' :
				return mssql_fetch_array($resource);
				break;
			case 'row' :
				return mssql_fetch_row($resource);
				break;
			default :
				return mssql_rows_affected($this->db_link);
		}
	}
	
	public function dataseek($resource, $row) {
		mssql_data_seek($resource, $row);
	}
	
	public function freeresult($resource) {
		mssql_free_result($resource);
	}
	
	public function close() {
		mssql_close($this->db_link);
	}
}

class dbClassMysql extends dbClass {
	private	$db_link;
	
	public function connect() {
		if (!$this->db_link = @mysql_connect($GLOBALS['mysql_servidor'], $GLOBALS['mysql_usuario'], $GLOBALS['mysql_senha'])) parent::error(1);
		if (!@mysql_select_db($GLOBALS['mysql_banco'], $this->db_link)) parent::error(2);
	}
	
	public function query($query) {
		return mysql_query($query, $this->db_link);
	}
	
	public function result($resource, $fetch = NULL) {
		switch ($fetch) {
			case 'object' :
				return mysql_fetch_object($resource);
				break;
			case 'array' :
				return mysql_fetch_array($resource);
				break;
			case 'row' :
				return mysql_fetch_row($resource);
				break;
			case 'insertid' :
				return mysql_insert_id($this->db_link);
				break;
			default :
				return mysql_affected_rows($this->db_link);
		}
	}
	
	public function dataseek($resource, $row) {
		mysql_data_seek($resource, $row);
	}
	
	public function freeresult($resource) {
		mysql_free_result($resource);
	}
	
	public function close() {
		mysql_close($this->db_link);
	}
}
?>

Utilização:

<?php
require("config.php");
require("class.inc.php");

$msdb = new dbClass();
$msdb->setdb('mssql');

$res = $msdb->query("SELECT count(*) FROM tabela");

list($total) = $msdb->result($res, 'row');
echo $total;

$msdb->freeresult($res);
$msdb->close();
?>

Se tiver alguma sugestão de como melhorar também seria bem aceita.

 

Abraços.

Compartilhar este post


Link para o post
Compartilhar em outros sites

João Batista Neto,

 

Achei muito legal o seu código.

 

Porém, pra aplicar o singleton mesmo aí complicou, pois a classe sendo abstrata, como tu fará para retornar UMA INSTÂNCIA da classe sendo que ela NÃO PODE SER INSTANCIADA?

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.