Protože váš Model
class vytvoří instanci nové Database
objekt ve svém konstruktoru, pokaždé, když vytvoříte instanci Model
(nebo jakoukoli třídu, která ji rozšiřuje), ve skutečnosti otevíráte novou připojení k databázi. Pokud vytvoříte několik Model
objekty, každý pak má své vlastní nezávislé databázové připojení, což je neobvyklé, obvykle zbytečné, není to dobré využití zdrojů, ale také aktivně škodlivé, protože vyčerpalo všechna dostupná připojení serveru.
Například smyčkování k vytvoření pole Model
objekty:
// 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)
Použít vložení závislosti:
Řešením je použít vkládání závislostí a pass Database
objekt do Model::__construct()
místo toho, aby mu umožnil vytvořit vlastní instanci.
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;
}
}
Chcete-li to potom použít, řídicí kód (kód, který vytvoří instanci vašich modelů) by měl sám volat new Database()
pouze jednou. Tento objekt vytvořený řídicím kódem pak musí být předán konstruktérům všech modelů.
// Instantiate one Database
$db = new Database();
// Pass it to models
$model = new Model($db);
Pro případ použití, kdy skutečně potřebujete pro model jiné nezávislé databázové připojení, mu můžete předat jiné. Zejména je to užitečné pro testování . Můžete nahradit objekt testovací databáze nebo falešný 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);
Trvalá připojení:
Jak je uvedeno v komentářích, použití trvalého připojení je možná řešení, ale ne řešení, které bych doporučil . PDO se pokusí znovu použít existující připojení se stejnými pověřeními (jako všechna vaše), ale nemusíte nutně chtít, aby se připojení ukládalo do mezipaměti při provádění skriptu. Pokud jste se rozhodli to udělat tímto způsobem, musíte atribut předat 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'");
}
Příslušná dokumentace je zde:http://php.net/manual /en/pdo.connections.php#example-950
Singleton řešení:
Pomocí jednobarevného vzoru (také se nedoporučuje) to můžete alespoň zredukovat na hledání/nahrazení v kódu modelu. Database
class potřebuje statickou vlastnost, aby si udržela připojení pro sebe. Modely pak volají Database::getInstance()
místo new Database()
pro obnovení připojení. Chcete-li nahradit Database::getInstance()
, museli byste provést vyhledávání a nahrazení v kódu modelu .
Ačkoli to funguje dobře a není obtížné jej implementovat, ve vašem případě by to trochu ztížilo testování, protože byste museli nahradit celou Database
třída se stejnojmennou testovací třídou. Testovací třídu nelze snadno nahradit instancí po instanci.
Použijte jednoduchý vzor na 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;
}
}
Nyní byste potřebovali změnit pouze Model
kód pro použití Database::getInstance()
:
class Model {
protected $_db;
public function __construct(){
// Retrieve the database singleton
$this->_db = Database::getInstance();
}
}