Tanto per fare un esempio, con tutti gli errori e i difetti del caso, oltre all'incompletezza della soluzione:
1) il parsing dei file di configurazione nonchè la loro gestione non può essere propria della classe che usa il db, quindi sposti tutto in un'altra classe che chiameremo per semplicità Configuration:
Codice PHP:
<?php
//Configuration.php
class Configuration{
const PATH_DELIMITER = '.';
private $configuration = array();
private $resource;
public function __construct($resource){
$this->resource = $resource;
$this->_parse();
}
private function _parse(){
if(is_readable($this->resource)===false)
throw new Exception("Impossibile aprire il file di configurazione ".$this->resource);
$this->configuration = parse_ini_file($this->resource,true);
}
public function get($path, $default = null){
$r = $this->search($path);
if($r['_found']===true)
{
return $r['_value'];
}
return $default;
}
public function set($path,$value){
$r = $this->search($path,true);
$r['_value'] = $value;
return $this;
}
private function search($path,$create = false){
$rit = array('_found' => false, '_value' => null);
$keys = explode(self::PATH_DELIMITER,$path);
if(!is_array($this->configuration))
{
if($this->configuration!==null)
$this->configuration = array($this->configuration);
else
$this->configuration = array();
}
$tmp =& $this->configuration;
$lastKeyI = count($keys)-1;
foreach($keys as $i => $key)
{
if(!is_array($tmp) || !array_key_exists($key, $tmp))
{
if(!$create)
break;
$tmp[$key] = array();
$tmp =& $tmp[$key];
}else if(array_key_exists($key, $tmp)){
if($i == $lastKeyI)
{
$rit['_found'] = true;
}
$tmp =& $tmp[$key];
}
$rit['_value'] =& $tmp;
}
if($rit['_found']===false && $create === false)
$rit['_value'] = null;
return $rit;
}
}
/*
esempio di utilizzo:
database.ini:
[database]
database = miodatabase
host = localhost
driver = pgsql
username = postgres
password =
$configuration = new Configuration('/path/to/database.ini');
print_r($configuration->get('database'));
echo $configuration->get('database.username');
$configuration->set('foo.bar',"foobar");
echo $configuration->get('foo.bar');
*/
2) Ispirandoci a questa classe: https://github.com/doctrine/dbal/blo...Connection.php proviamo a fare noi un esempio:
Codice PHP:
<?php
//DB.php
class DB{
/**
*
* @var PDO
*/
private $pdo;
private $database;
private $driver;
private $username;
private $password;
private $host;
private $port;
private $connected;
public $lastError;
public function __construct($database='',$driver='',$username='',$password='',$host='',$port=0) {
$this->database = $database;
$this->driver = $driver;
$this->username = $username;
$this->password = $password;
$this->host = $host;
$this->port = $port;
$this->connected = false;
}
public function getDatabase(){
return $this->database;
}
public function setDatabase($database){
$this->database = $database;
return $this;
}
//altri getter/setter per driver/username/password/host/port
public function connect(){
if($this->isConnected())
throw new Exception('Connessione già attiva');
try{
$dsn = $this->getDSN();
$this->pdo = new PDO($dsn, $this->username, $this->password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$this->connected = true;
}catch(PDOException $ex){
$this->pdo = null;
$this->connected = false;
//intercetto tutte le mie eccezioni e le gestisco come ritengo più opportuno
//ma eviterei di propagare PDOExceptions fuori da questa classe
//perchè è suo compito gestirle, al limite rilanciando eccezioni di
//diverso tipo relative alla tua applicazione definite con altre classi
$this->lastError = $ex->getMessage();
}
return $this->isConnected();
}
public function isConnected(){
return $this->connected && $this->pdo !== null;
}
private function getDSN(){
return $this->driver .
':host=' . $this->host .
( $this->port ? ';port=' . $this->port : '') .
';dbname=' . $this->database;
}
//ci metto tutte le funzioni esposte da PDO che mi pare, usandole in maniera più friendly, es:
public function fetchAll($sql, array $params = array())
{
return $this->executeQuery($sql, $params)->fetchAll();
}
public function delete($tableName,array $params = array()){
$criteria = array();
foreach(array_keys($params) as $columnName)
{
$criteria[] = $columnName.' = ?';
}
$sql = 'DELETE FROM '.$tableName.' WHERE '.implode(' AND ',$criteria);
return $this->executeUpdate($sql, array_values($params));
}
public function executeQuery($sql,array $params = array()){
//PDOStatement
$smt = null;
if($params)
{
$smt = $this->pdo->prepare($sql);
foreach($params as $key => $value)
{
if(is_numeric($key))
$smt->bindValue($key+1, $value);
else
$smt->bindValue (":$key", $value);
}
$smt->execute();
}else{
$smt = $this->pdo->query($sql);
}
return $smt;
}
public function executeUpdate($sql, array $params = array()){
$result = 0;
if($params)
{
$smt = $this->pdo->prepare($sql);
foreach($params as $key => $value)
{
if(is_numeric($key))
$smt->bindValue($key+1, $value);
else
$smt->bindValue (":$key", $value);
}
$smt->execute();
$result = $smt->rowCount();
}else{
$result = $this->pdo->exec($sql);
}
return $result;
}
public function beginTransaction(){
//..
}
public function commit(){
//..
}
}
3) Mettiamo tutto insieme:
Codice PHP:
include_once "Configuration.php";
include_once "DB.php";
$configuration = new Configuration(__DIR__.DIRECTORY_SEPARATOR.'database.ini');
$db = new DB($configuration->get('database.database'),
$configuration->get('database.driver'),
$configuration->get('database.username'),
$configuration->get('database.password'),
$configuration->get('database.host'));
if(!$db->connect())
die($db->lastError);
foreach($db->fetchAll("select * from users") as $row){
print_r($row);
}
foreach($db->fetchAll("select * from users where id = ?",array('114')) as $row){
print_r($row);
}
echo "deleted: ".$db->delete('users',array('id'=>127));
Ovviamente, se tu nel tuo progetto ti includi la libreria di Doctrine e usi soltanto o inizia partendo dall'usare la loro Classe Connection.php, avrai già fatto e debuggato un ottimo strumento.