Model
クラスは新しい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)
依存性注入を使用する:
解決策は、依存性注入と passを使用することです。 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()
を呼び出す必要があります。 1回だけ。次に、制御コードによって作成されたそのオブジェクトを、すべてのモデルのコンストラクターに渡す必要があります。
// 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 /en/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();
}
}