问题
Sorry for poor english, I'm Brazilian, and even worse talking about programming. Let's go. I have this:
class DataBase extends PDO
{
/**
* @var object PDO
*/
private static $instance;
/**
* Cria uma instância do PDO representando a conexão ao banco de dados e torna a instância disponível como "singleton"
*
* @param string $dsn O DSN completo, ex.: mysql:host=localhost;dbname=testdb
* @param string $username O nome de usuário para a string DSN. Esse parâmetro é opcional para alguns drivers do PDO.
* @param string $password A senha para a string DSN. Esse parâmetro é opcional para alguns drivers do PDO.
* @param array $driver_options Um array key => value de opções de conexão específicas do driver
*
* @return PDO
*/
public
function __construct()
{
global $config;
$dsn = "mysql:dbname={$config['database'][AMBIENTE]['banco']};host={$config['database'][AMBIENTE]['url']}";
$username = $config['database'][AMBIENTE]['usuario'];
$password = $config['database'][AMBIENTE]['senha'];
if ( !isset ( self::$instance ) )
{
try
{
self::$instance = parent::__construct( $dsn , $username , $password );
}
catch ( PDOException $e )
{
Functions::Log( 'Erro de conexão de banco de dados: ' . $e->getMessage() );
header( 'HTTP/1.1 500 Internal Server Error' );
}
}
$this->storage = new ArrayObject();
}
public static
function getInstance()
{
if ( !self::$instance )
{
self::$instance = new DataBase;
}
return self::$instance;
}
}
and the model that extends the class DataBase:
class Model extends DataBase
{
protected $TABLE_NAME;
protected $TABLE_PREFIX;
/* all logic here, like getters, setters and methods like update, delete and insert... */
}
But I can't use the $this variable to access the PDO methods like query OR prepare. It's says that I'm not called the PDO constructor, even if my Model class constructor call getInstance.
It's possible?
回答1:
To make your example work, you might try this.
define('DB_CONN','mysql:dbname=;host=');
define('DB_USER', '');
define('DB_PASS', '');
interface iMySQL
{
public
function query( $string );
public
function select();
public
function selectAll();
public
function insert();
public
function update();
public
function delete();
public
function load();
}
class DataBase
{
/**
* @var object PDO
*/
private static $instance = null;
/**
* Cria uma instância do PDO representando a conexão ao banco de dados e torna a instância disponível como "singleton"
*
* @param string $dsn O DSN completo, ex.: mysql:host=localhost;dbname=testdb
* @param string $username O nome de usuário para a string DSN. Esse parâmetro é opcional para alguns drivers do PDO.
* @param string $password A senha para a string DSN. Esse parâmetro é opcional para alguns drivers do PDO.
* @param array $driver_options Um array key => value de opções de conexão específicas do driver
*
*/
private function __construct() {
}
public static function getInstance()
{
if ( self::$instance === null )
{
self::$instance = new PDO(DB_CONN, DB_USER, DB_PASS);
}
return self::$instance;
}
}
class Model
{
protected $TABLE_NAME;
protected $TABLE_PREFIX;
protected $clausula;
private $storage;
/**
* Recupera um registro utilizando sua chave
*
* @param string $key
*
* @return mixed O valor armazenado
* @throws RuntimeException Se não houver um registro para a chave especificada
*/
public
function __get( $key )
{
}
/**
* Registra um valor à uma chave
*
* @param string $key A chave que será utilizada no registro
* @param mixed $value O valor que será registrado
*
* @throws LogicException Se a chave já estiver registrada
*/
public
function __set( $key , $value )
{
//echo $key;
}
public static
function __callStatic( $method , $args )
{
$database = DataBase::getInstance();
$callback = array( $database , $method );
return call_user_func_array( $callback , $args );
}
public
function __call( $method , $args )
{
$database = DataBase::getInstance();
$callback = array( $database , $method );
return call_user_func_array( $callback , $args );
}
public function __construct( $table_name = null , $id = null )
{
$this->TABLE_PREFIX = $this->config['database']['table_prefix'];
$this->TABLE_NAME = $this->TABLE_PREFIX . $table_name;
$this->storage = new ArrayObject();
if ( !is_null( $table_name ) )
{
$array = $this->query( "SHOW COLUMNS FROM `$this->TABLE_NAME`" )->fetchAll();
$colunas = array();
$obrigatorias = array();
foreach ( $array as $value )
{
$colunas[] = $value[0];
if ( $value['Null'] === 'NO' )
{
$obrigatorias[] = $value['Field'];
}
}
$this->colunas = $colunas;
$this->obrigatorias = $obrigatorias;
$this->total_colunas = count( $this->colunas );
// Se passou um id por parâmetro, salva nas propriedades do objeto
if ( !is_null( $id ) AND is_numeric( $id ) )
{
$this->id = $id;
// E já carrega o objeto
$select = $this->query( 'SELECT * FROM {tabela_nome} WHERE `id` = ' . $id )->fetchObject();
$this->load( $select );
}
}
}
public
function insert()
{
}
public
function update()
{
}
public
function delete()
{
}
public
function select( $clausula = NULL , $is_array = FALSE )
{
// Caso seja passado uma cláusula diretamente para a função, executa ela
if ( !is_null( $clausula ) )
{
$this->clausula = $clausula;
}
// Troca uma possível variável pelo nome da tabela do Model
$this->clausula = ( str_replace( '{TABLE_NAME}' , $this->TABLE_NAME , $this->clausula ) );
$this->clausula = ( str_replace( '{TABLE_PREFIX}' , $this->TABLE_PREFIX , $this->clausula ) );
// Executa o SELECT no banco de dados
$query = $this->query( $this->clausula );
if ( $query AND $query->rowCount() > 0 )
{
if ( $query->rowCount() == 1 AND !$is_array )
{
return $query->fetchObject( get_class( $this ) );
}
else
{
$objetos = array();
while ( $linha = $query->fetchObject( get_class( $this ) ) )
{
$objetos[] = $linha;
}
return ( count( $objetos ) > 0 ) ? $objetos : FALSE;
}
}
else
{
return FALSE;
}
}
public
function selectAll()
{
}
public
function load()
{
}
}
$model = new Model();
$stmt = $model->query();
$fetch = $stmt->fetchAll();
var_dump($fetch);
This is not tested. But it should give you an idea how to solve the problem. Try this approach.
define('DB_TYPE', 'DB_Class_One');
class DB_Class_One extends PDO {
public function getData() {
print 'Class One';
}
}
class DB_Class_Two extends PDO {
public function getData() {
print 'Class Two';
}
}
class DB_Class_Three extends PDO {
public function getData() {
print 'Class Three';
}
}
class DataBase {
private static $instance = null;
private function __construct() {
}
private function __clone() {
}
public static function getInstance() {
$class = DB_TYPE;
if (self::$instance === null) {
self::$instance = new $class("mysql:host=;dbname=", '', '');
}
return self::$instance;
}
}
$db = DataBase::getInstance();
$stmt = $db->query();
$result = $stmt->fetch();
$db->getData();
回答2:
Something seems funny about your getInstance()
method and your constructor both assigning to self::$instance
:
function getInstance()
{
if ( !self::$instance )
{
self::$instance = new DataBase;
}
/* .... */
function __construct()
{
/* .... */
if ( !isset ( self::$instance ) )
{
try
{
self::$instance = parent::__construct( $dsn , $username , $password );
}
Remove the assignment from getInstance()
and see if that works.
来源:https://stackoverflow.com/questions/9337989/singleton-pdo-model-hierarchy