Perché il tuo Model
class istanzia un nuovo Database
oggetto nel suo costruttore, ogni volta che istanzia un Model
(o qualsiasi classe che lo estenda), stai in effetti aprendo un nuovo connessione al database. Se crei diversi Model
oggetti, ognuno ha quindi la propria connessione al database indipendente, che è rara, di solito non necessaria, non un buon uso delle risorse, ma anche attivamente dannosa in quanto ha esaurito tutte le connessioni disponibili del server.
Ad esempio, eseguire un ciclo per creare un array di Model
oggetti:
// If a loop creates an array of Model objects
while ($row = $something->fetch()) {
$models[] = new Model();
}
// each object in $models has an independent database connection
// the number of connections now in use by MySQL is now == count($models)
Utilizza l'inserimento delle dipendenze:
La soluzione consiste nell'usare l'inserimento delle dipendenze e passa il Database
oggetto nel Model::__construct()
piuttosto che consentirgli di creare un'istanza.
class Model {
protected $_db;
// Accept Database as a parameter
public function __construct(Database $db) {
// Assign the property, do not instantiate a new Database object
$this->_db = $db;
}
}
Per usarlo quindi, il codice di controllo (il codice che istanzia i tuoi modelli) dovrebbe esso stesso chiamare new Database()
solo una volta. L'oggetto creato dal codice di controllo deve quindi essere passato ai costruttori di tutti i modelli.
// Instantiate one Database
$db = new Database();
// Pass it to models
$model = new Model($db);
Per il caso d'uso in cui hai effettivamente bisogno di una connessione al database indipendente diversa per un modello, puoi consegnarne una diversa. In particolare, questo è utile per i test . Puoi sostituire un oggetto database di prova o un oggetto fittizio.
// Instantiate one Database
$db = new Database();
$another_db = new Database();
// Pass it to models
$model = new Model($db);
$another_model = new Model($another_db);
Connessioni persistenti:
Come accennato nei commenti, l'utilizzo di una connessione persistente è probabilmente una soluzione, ma non è la soluzione che consiglierei . PDO tenterà di riutilizzare una connessione esistente con le stesse credenziali (come tutte le tue avranno), ma non si desidera necessariamente che la connessione venga memorizzata nella cache durante l'esecuzione dello script. Se hai deciso di farlo in questo modo, devi passare l'attributo al Database
costruttore.
try {
// Set ATTR_PERSISTENT in the constructor:
parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS, array(PDO::ATTR_PERSISTENT => true));
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
La documentazione pertinente è qui:http://php.net/manual /it/pdo.connections.php#example-950
Soluzione singleton:
Utilizzando un pattern singleton (anch'esso sconsigliato), potresti almeno ridurlo a una ricerca/sostituzione nel codice del modello. Il Database
class ha bisogno di una proprietà statica per mantenere una connessione per sé. I modelli quindi chiamano Database::getInstance()
invece di new Database()
per recuperare la connessione. Dovresti eseguire una ricerca e sostituire nel codice del modello per sostituire Database::getInstance()
.
Sebbene funzioni bene e non sia difficile da implementare, nel tuo caso renderebbe i test un po' più difficili poiché dovresti sostituire l'intero Database
classe con una classe di test con lo stesso nome. Non puoi sostituire facilmente una classe di test istanza per istanza.
Applica il pattern singleton a Database
:
class Database extends PDO{
// Private $connection property, static
private static $connection;
// Normally a singleton would necessitate a private constructor
// but you can't make this private while the PDO
// base class exposes it as public
public function __construct(){
try {
parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
} catch(PDOException $e){
Logger::newMessage($e);
logger::customErrorMsg();
}
}
// public getInstance() returns existing or creates new connection
public static function getInstance() {
// Create the connection if not already created
if (self::$connection == null) {
self::$connection = new self();
}
// And return a reference to that connection
return self::$connection;
}
}
Ora dovresti cambiare solo il Model
codice da utilizzare Database::getInstance()
:
class Model {
protected $_db;
public function __construct(){
// Retrieve the database singleton
$this->_db = Database::getInstance();
}
}