Ponieważ Twój Model
klasa tworzy instancję nowej Database
w swoim konstruktorze, za każdym razem, gdy tworzysz instancję Model
(lub dowolną klasę ją rozszerzającą), w efekcie otwierasz nową połączenie z bazą danych. Jeśli utworzysz kilka Model
obiektów, każdy ma wtedy własne niezależne połączenie z bazą danych, co jest rzadkie, zwykle niepotrzebne, nie jest dobrym wykorzystaniem zasobów, ale także jest aktywnie szkodliwe, ponieważ wykorzystuje wszystkie dostępne połączenia serwera.
Na przykład zapętlenie w celu utworzenia tablicy Model
obiekty:
// 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)
Użyj wstrzykiwania zależności:
Rozwiązaniem jest użycie wstrzykiwania zależności i pass Database
do obiektu Model::__construct()
zamiast pozwalać mu na tworzenie własnego wystąpienia.
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;
}
}
Aby go wtedy użyć, kod kontrolujący (kod, który będzie tworzył instancje twoich modeli) powinien sam wywołać new Database()
tylko raz. Ten obiekt utworzony przez kod kontrolujący musi następnie zostać przekazany do konstruktorów wszystkich modeli.
// Instantiate one Database
$db = new Database();
// Pass it to models
$model = new Model($db);
W przypadku użycia, w którym faktycznie potrzebujesz innego niezależnego połączenia z bazą danych dla modelu, możesz przekazać mu inne. Jest to szczególnie przydatne do testowania . Możesz podstawić testowy obiekt bazy danych lub obiekt próbny.
// Instantiate one Database
$db = new Database();
$another_db = new Database();
// Pass it to models
$model = new Model($db);
$another_model = new Model($another_db);
Stałe połączenia:
Jak wspomniano w komentarzach, używanie stałego połączenia jest prawdopodobnie rozwiązaniem, ale nie rozwiązaniem, które polecam . PDO spróbuje ponownie użyć istniejącego połączenia z tymi samymi poświadczeniami (jak wszystkie twoje), ale niekoniecznie chcesz, aby połączenie było buforowane podczas wykonywania skryptu. Jeśli zdecydowałeś się zrobić to w ten sposób, musisz przekazać atrybut do Database
konstruktor.
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'");
}
Odpowiednia dokumentacja jest tutaj:http://php.net/manual /pl/pdo.connections.php#example-950
Rozwiązanie jednotonowe:
Używając wzorca singleton (również niezalecanego), możesz przynajmniej zredukować to do wyszukiwania/zamieniania w kodzie modelu. Database
class potrzebuje właściwości statycznej, aby utrzymać połączenie dla siebie. Modele następnie wywołują Database::getInstance()
zamiast new Database()
aby odzyskać połączenie. Będziesz musiał przeprowadzić wyszukiwanie i zamianę w kodzie modelu, aby zastąpić Database::getInstance()
.
Chociaż działa dobrze i nie jest trudna do zaimplementowania, w twoim przypadku sprawiłoby to, że testowanie byłoby trochę trudniejsze, ponieważ musiałbyś wymienić całą Database
klasa z klasą testową o tej samej nazwie. Nie możesz łatwo zastąpić klasy testowej na podstawie instancji po instancji.
Zastosuj pojedynczy wzór do 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;
}
}
Teraz musiałbyś zmienić tylko Model
kod do użycia Database::getInstance()
:
class Model {
protected $_db;
public function __construct(){
// Retrieve the database singleton
$this->_db = Database::getInstance();
}
}