Тъй като вашият Model
class създава нова Database
обект в неговия конструктор, всеки път, когато инстанцирате Model
(или който и да е клас, който го разширява), всъщност отваряте нов връзка с базата данни. Ако създадете няколко Model
обекти, всеки след това има своя собствена независима връзка с базата данни, която е необичайна, обикновено ненужна, не използва добре ресурсите, но също така активно е вредна, тъй като е използвала всички налични връзки на сървъра.
Например, цикъл за създаване на масив от Model
обекти:
// 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)
Използване на инжектиране на зависимост:
Решението е да използвате инжектиране на зависимост и пропускане Database
обект в Model::__construct()
вместо да му позволите да създаде своя собствена.
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;
}
}
За да го използвате тогава, управляващият код (кодът, който ще инстанцира вашите модели) трябва сам да извика new Database()
само веднъж. След това този обект, създаден от управляващия код, трябва да бъде предаден на конструкторите на всички модели.
// Instantiate one Database
$db = new Database();
// Pass it to models
$model = new Model($db);
За случая на използване, когато всъщност се нуждаете от различна независима връзка с база данни за модел, можете да му предоставите различна. По-специално, това е полезно за тестване . Можете да замените обект на тестова база данни или фалшив обект.
// Instantiate one Database
$db = new Database();
$another_db = new Database();
// Pass it to models
$model = new Model($db);
$another_model = new Model($another_db);
Постоянни връзки:
Както бе споменато в коментарите, използването на постоянна връзка е вероятно решение, но не решението, което бих препоръчал . PDO ще се опита да използва повторно съществуваща връзка със същите идентификационни данни (както всички ваши ще имат), но не е задължително да искате връзката да се кешира при изпълнение на скрипта. Ако все пак сте решили да го направите по този начин, трябва да предадете атрибута на Database
конструктор.
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'");
}
Съответната документация е тук:http://php.net/manual /bg/pdo.connections.php#example-950
Единично решение:
Използвайки единичен модел (също не се препоръчва), можете поне да намалите това до търсене/замяна в кода на модела. Database
класът се нуждае от статично свойство, за да запази връзка за себе си. След това моделите извикват Database::getInstance()
вместо new Database()
за да извлечете връзката. Ще трябва да направите търсене и да замените в кода на модела, за да замените Database::getInstance()
.
Въпреки че работи добре и не е труден за внедряване, във вашия случай ще направи тестването малко по-трудно, тъй като ще трябва да замените цялата Database
клас с тестов клас със същото име. Не можете лесно да замените тестов клас на база екземпляр по екземпляр.
Прилагане на единичен модел към 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;
}
}
Сега ще трябва да промените само Model
код за използване на Database::getInstance()
:
class Model {
protected $_db;
public function __construct(){
// Retrieve the database singleton
$this->_db = Database::getInstance();
}
}