Fordi din Model
klasse instansierer en ny Database
objekt i dets konstruktør, hver gang du instansierer en Model
(eller en hvilken som helst klasse, der udvider den), åbner du faktisk en ny database forbindelse. Hvis du opretter flere Model
objekter, har hver så sin egen uafhængige databaseforbindelse, hvilket er ualmindeligt, normalt unødvendigt, ikke en god brug af ressourcer, men også aktivt skadeligt, da det har brugt alle serverens tilgængelige forbindelser.
For eksempel looping for at skabe en matrix af Model
objekter:
// 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)
Brug afhængighedsinjektion:
Løsningen er at bruge afhængighedsinjektion og pass Database
objekt ind i Model::__construct()
i stedet for at tillade den at instansiere sin egen.
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;
}
}
For at bruge det derefter, bør den kontrollerende kode (koden, som vil instansiere dine modeller) selv kalde new Database()
kun én gang. Det objekt, der er oprettet af den kontrollerende kode, skal derefter videregives til konstruktørerne af alle modeller.
// Instantiate one Database
$db = new Database();
// Pass it to models
$model = new Model($db);
I det tilfælde, hvor du faktisk har brug for en anden uafhængig databaseforbindelse til en model, kan du give den en anden. Dette er især nyttigt til test . Du kan erstatte et testdatabaseobjekt eller et falsk objekt.
// Instantiate one Database
$db = new Database();
$another_db = new Database();
// Pass it to models
$model = new Model($db);
$another_model = new Model($another_db);
Vedholdende forbindelser:
Som nævnt i kommentarerne er brug af en vedvarende forbindelse muligvis en løsning, men ikke den løsning, jeg vil anbefale . PDO vil forsøge at genbruge en eksisterende forbindelse med de samme legitimationsoplysninger (som alle dine vil have), men du ønsker ikke nødvendigvis, at forbindelsen skal cachelagres på tværs af scriptudførelse. Hvis du besluttede dig for at gøre det på denne måde, skal du videregive attributten til Database
konstruktør.
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'");
}
Den relevante dokumentation er her:http://php.net/manual /da/pdo.connections.php#example-950
Singleton-løsning:
Ved at bruge et singleton-mønster (også ikke anbefalet), kan du i det mindste reducere dette til en søgning/erstatning i modelkoden. Database
klasse har brug for en statisk egenskab for at holde en forbindelse for sig selv. Modeller kalder derefter Database::getInstance()
i stedet for new Database()
for at hente forbindelsen. Du skal søge og erstatte modelkoden for at erstatte Database::getInstance()
.
Selvom det fungerer godt og ikke er svært at implementere, ville det i dit tilfælde gøre testningen lidt sværere, da du skulle erstatte hele Database
klasse med en testklasse af samme navn. Du kan ikke nemt erstatte en testklasse fra instans til instans.
Anvend singleton-mønster på 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;
}
}
Nu skal du kun ændre Model
kode for at bruge Database::getInstance()
:
class Model {
protected $_db;
public function __construct(){
// Retrieve the database singleton
$this->_db = Database::getInstance();
}
}