Karena Model
your Anda class membuat Database
baru objek di konstruktornya, setiap kali Anda membuat Model
(atau kelas apa pun yang memperluasnya), Anda sebenarnya membuka baru koneksi basis data. Jika Anda membuat beberapa Model
objek, masing-masing kemudian memiliki koneksi database independennya sendiri, yang jarang terjadi, biasanya tidak diperlukan, bukan penggunaan sumber daya yang baik, tetapi juga berbahaya secara aktif karena telah menghabiskan semua koneksi server yang tersedia.
Misalnya, perulangan untuk membuat larik Model
objek:
// 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)
Gunakan injeksi ketergantungan:
Solusinya adalah dengan menggunakan injeksi ketergantungan dan lulus Database
objek ke dalam Model::__construct()
daripada membiarkannya membuat instance-nya sendiri.
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;
}
}
Untuk menggunakannya, kode pengontrol (kode yang akan membuat instance model Anda) harus memanggil sendiri new Database()
hanya sekali. Objek yang dibuat oleh kode pengontrol kemudian harus diteruskan ke konstruktor semua model.
// Instantiate one Database
$db = new Database();
// Pass it to models
$model = new Model($db);
Untuk kasus penggunaan di mana Anda benar-benar membutuhkan koneksi database independen yang berbeda untuk suatu model, Anda dapat memberikannya yang berbeda. Secara khusus, ini berguna untuk pengujian . Anda dapat mengganti objek database pengujian, atau objek tiruan.
// Instantiate one Database
$db = new Database();
$another_db = new Database();
// Pass it to models
$model = new Model($db);
$another_model = new Model($another_db);
Koneksi persisten:
Seperti yang disebutkan dalam komentar, menggunakan koneksi persisten mungkin merupakan solusi, tetapi bukan solusi yang saya rekomendasikan . PDO akan mencoba untuk menggunakan kembali koneksi yang ada dengan kredensial yang sama (seperti semua milik Anda), tetapi Anda tidak perlu ingin koneksi di-cache di seluruh eksekusi skrip. Jika Anda memutuskan untuk melakukannya dengan cara ini, Anda harus meneruskan atribut ke 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'");
}
Dokumentasi yang relevan ada di sini:http://php.net/manual /en/pdo.connections.php#example-950
Solusi tunggal:
Menggunakan pola tunggal (juga tidak disarankan), Anda setidaknya bisa mengurangi ini menjadi pencarian/penggantian dalam kode model. Database
kelas membutuhkan properti statis untuk menjaga koneksi untuk dirinya sendiri. Model kemudian memanggil Database::getInstance()
alih-alih new Database()
untuk mengambil koneksi. Anda perlu melakukan pencarian dan mengganti kode Model untuk menggantikan Database::getInstance()
.
Meskipun bekerja dengan baik dan tidak sulit untuk diimplementasikan, dalam kasus Anda itu akan membuat pengujian sedikit lebih sulit karena Anda harus mengganti seluruh Database
kelas dengan kelas pengujian dengan nama yang sama. Anda tidak dapat dengan mudah mengganti kelas pengujian berdasarkan instance demi instance.
Terapkan pola tunggal ke 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;
}
}
Sekarang Anda hanya perlu mengubah Model
kode untuk menggunakan Database::getInstance()
:
class Model {
protected $_db;
public function __construct(){
// Retrieve the database singleton
$this->_db = Database::getInstance();
}
}