目次
PHPアプリケーションにおけるDB接続管理にデザインパターンの一つであるSingletonを適用する例を紹介します。
Singletonパターンについての概要は以下の記事で詳しく紹介しています。
https://zenn.dev/kenchang198/articles/1d1c5ce80b7460
環境:PHP 8.2.28
この記事で紹介するすべてのソースコードはGitHubリポジトリで公開しています。詳細な実装やサンプルコードはそちらから参照してください。
データベース接続とSingletonパターン
データベース接続は、Singletonパターンの代表的な適用例です。接続の初期化コストを削減し、リソースを効率的に利用するために、アプリケーション全体で単一のインスタンスを共有します。
Singletonパターンを使用したDatabaseManagerの実装
DatabaseManagerクラスの核となる部分を以下に示します:
class DatabaseManager
{
// 唯一のインスタンス
private static $instance = null;
// データベース接続インスタンス
private $connection = null;
// コンストラクタをprivateに
private function __construct() {
// デフォルト設定
$this->config = [
'host' => 'mysql',
'database' => 'sample_db',
'username' => 'sample_user',
'password' => 'sample_password'
];
}
// cloneを禁止
private function __clone() {}
// unserializeを禁止(PHP 8対応)
public function __wakeup() {
throw new Exception("Cannot unserialize a singleton.");
}
// インスタンスを取得
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// 接続を取得(シングルトンパターンで実装)
public function getConnection() {
if ($this->connection === null) {
try {
// PDO接続の作成
$this->connection = new PDO(
"mysql:host={$this->config['host']};dbname={$this->config['database']}",
$this->config['username'],
$this->config['password']
);
} catch (PDOException $e) {
throw new Exception("データベース接続エラー: " . $e->getMessage());
}
}
return $this->connection;
}
}
DatabaseManagerの使用例
複数の場所から同じデータベース接続にアクセスする例:
// DatabaseManagerのインスタンスを取得
$dbManager = DatabaseManager::getInstance();
// 別のクラスでも同じ接続を再利用
class ProductService {
public function getMostExpensiveProduct() {
// どこからでも同じインスタンスにアクセス可能
$dbManager = DatabaseManager::getInstance();
return $dbManager->fetchOne("SELECT * FROM products ORDER BY price DESC LIMIT 1");
}
}
Singletonパターンがデータベース接続に適している理由
- リソース効率: データベース接続は高コストな操作のため、一つの接続を共有することで効率化
- 状態の一貫性: アプリケーション全体で一貫したデータベース状態を維持
- 接続数の制限: データベースの同時接続数制限対策
- 設定の一元管理: 接続設定を一箇所で管理可能
データベース接続におけるSingletonパターンの注意点
- 接続の生存期間: PHPではリクエスト間で接続は維持されない
- 複数データベース対応: 複数DB使用時は設計拡張が必要
- テスト容易性: モックに置き換えが難しい場合がある
- スケーラビリティ: 高負荷環境では接続プールなど他のアプローチとの併用検討
ベストプラクティス
- 責任の分離: データベース接続とクエリ実行に専念させる
- シンプルなインターフェース: 必要最小限のメソッドのみ公開
- 柔軟な設定: 環境に応じた設定変更を可能に
- 適切な例外処理: エラーを明確に通知
まとめ
データベース接続はSingletonパターンの理想的な適用例です。リソース効率化と状態の一貫性を実現しながら、複数の場所から同じ接続にアクセスできます。ただし、テスト容易性や責任分離なども考慮した設計が重要です。