Php 如何通过重用提高数据库对象的效率
我对如何处理重用数据库对象和代表应用程序全局的配置变量或常量的逻辑感到困惑 到目前为止,我一直在做的是,我在Php 如何通过重用提高数据库对象的效率,php,design-patterns,singleton,Php,Design Patterns,Singleton,我对如何处理重用数据库对象和代表应用程序全局的配置变量或常量的逻辑感到困惑 到目前为止,我一直在做的是,我在config目录中创建了一个config.php文件,并声明所有config元素,例如,我的典型config.php文件如下所示 #Start Session session_start(); #Start Output Buffering ob_start(); #Set Default TimeZone date_default_timezone_set('Asia/Kolkata')
config
目录中创建了一个config.php
文件,并声明所有config
元素,例如,我的典型config.php文件如下所示
#Start Session
session_start();
#Start Output Buffering
ob_start();
#Set Default TimeZone
date_default_timezone_set('Asia/Kolkata');
#Define Time Constant
define('DATE', date("d-F-Y/H:ia"));
#Define Paths
define('CLASSES',$_SERVER['DOCUMENT_ROOT'].'/resources/library/classes/');
define('MODELS',$_SERVER['DOCUMENT_ROOT'].'/resources/library/models/');
define('LOGS',$_SERVER['DOCUMENT_ROOT'].'/resources/logs/');
#Define Connection Constant
define('HOST','localhost');
define('USERNAME','username');
define('PASSWORD','password');
define('DATABASE','dbname');
try
{
#Connection String.
$dbh = new PDO('mysql:host='.HOST.';dbname='.DATABASE,USERNAME,PASSWORD);
#Set Error Mode to ERRMODE_EXCEPTION.
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
#Print Errors.
echo $e->getMessage();
#Log Errors into a file
file_put_contents(LOGS.'Connection-log.txt', DATE.PHP_EOL.$e->getMessage().PHP_EOL.PHP_EOL, FILE_APPEND);
}
#Autoload Classes.
function __autoload($class) {
require_once CLASSES.'class.'.strtolower($class).'.php';
}
if(isset($_GET['users'])) {
require_once(MODELS.'users/users.php');
} else if(isset($_GET['categories'])) {
require_once(MODELS.'categories/categories.php');
} else if(isset($_GET['search'])) {
require_once(MODELS.'search/search.php');
}
在index.php文件中,我将包含这个文件一次,并在每个对象中重复使用它
php通常由如下控制器组成
#Start Session
session_start();
#Start Output Buffering
ob_start();
#Set Default TimeZone
date_default_timezone_set('Asia/Kolkata');
#Define Time Constant
define('DATE', date("d-F-Y/H:ia"));
#Define Paths
define('CLASSES',$_SERVER['DOCUMENT_ROOT'].'/resources/library/classes/');
define('MODELS',$_SERVER['DOCUMENT_ROOT'].'/resources/library/models/');
define('LOGS',$_SERVER['DOCUMENT_ROOT'].'/resources/logs/');
#Define Connection Constant
define('HOST','localhost');
define('USERNAME','username');
define('PASSWORD','password');
define('DATABASE','dbname');
try
{
#Connection String.
$dbh = new PDO('mysql:host='.HOST.';dbname='.DATABASE,USERNAME,PASSWORD);
#Set Error Mode to ERRMODE_EXCEPTION.
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
#Print Errors.
echo $e->getMessage();
#Log Errors into a file
file_put_contents(LOGS.'Connection-log.txt', DATE.PHP_EOL.$e->getMessage().PHP_EOL.PHP_EOL, FILE_APPEND);
}
#Autoload Classes.
function __autoload($class) {
require_once CLASSES.'class.'.strtolower($class).'.php';
}
if(isset($_GET['users'])) {
require_once(MODELS.'users/users.php');
} else if(isset($_GET['categories'])) {
require_once(MODELS.'categories/categories.php');
} else if(isset($_GET['search'])) {
require_once(MODELS.'search/search.php');
}
在模型中,我会实例化我想要的对象,并在users/users.php中使用它,我会像这样实例化它
$user=新用户($dbh)代码>
一切正常,但问题是对于每个类,我都必须通过构造函数传递数据库句柄对象,并在类中重用它,这对我来说有点难看。如果我想使用包含静态方法和属性的类来保存要从数据库检索的应用程序设置,这种方法会给我带来一个问题。我的要求是这样的
我想使用单例模式创建一个静态方法,该方法将保存要在整个应用程序中使用的数据库对象,而无需每次通过每个类的构造函数传递$dbh
对象。我很困惑我该如何处理这个问题
谢谢我有一个类似的设计模式,我将连接和存储在一个全局数据库中
您不需要将数据库变量传递给每个类,因为它是一个全局变量
您可以在任何地方使用它,如下所示:
$GLOBALS['dbh'];
function get_db_connection(){
if(isset($GLOBALS['db_conn']) && get_class($GLOBALS['db_conn']) == 'PDO'){
return $GLOBALS['db_conn'];
}else{
$conn = new PDO(/* parameters */);
$GLOBALS['db_conn'] = &$conn;
return $conn;
}
}
function cnn() {
static $pdo;
if(!isset($pdo)) {
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
$pdo->setAttribute(PDO::ATTR_TIMEOUT, 30);
$pdo->setAttribute(PDO::ATTR_PERSISTENT, true);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
return $pdo;
} else {
return $pdo;
}
}
为了隐藏这一点,我实际上创建了一个名为get\u db\u connection()
的函数,该函数首先检查$GLOBALS
数组中是否存在有效连接,然后返回它。此外,如果没有有效连接,它将创建一个新连接,并将其存储在$GLOBALS中并返回
它还有一个额外的好处,就是我确实需要在任何地方手动实例化连接,它在第一次调用get\u db\u connection
时自动创建,随后在任何地方都可用
get\u db\u connection
函数如下所示:
$GLOBALS['dbh'];
function get_db_connection(){
if(isset($GLOBALS['db_conn']) && get_class($GLOBALS['db_conn']) == 'PDO'){
return $GLOBALS['db_conn'];
}else{
$conn = new PDO(/* parameters */);
$GLOBALS['db_conn'] = &$conn;
return $conn;
}
}
function cnn() {
static $pdo;
if(!isset($pdo)) {
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
$pdo->setAttribute(PDO::ATTR_TIMEOUT, 30);
$pdo->setAttribute(PDO::ATTR_PERSISTENT, true);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
return $pdo;
} else {
return $pdo;
}
}
有利于全球的防御
由于以下原因,我认为这是一个可原谅的全局用法:
- 变量$dbh已经是全局变量,因为它不在函数中
或者一个班级李>
- 您不能在任何地方直接访问全局数据库
您的程序,但仅通过一个函数
get\u db\u connection
因此,任何人都可以改变全球价值的问题并不存在
在这里李>
- 唯一的解决方法是使用单例,这可能是
对于这样一个简单的问题没有必要李>
这些问题我认为是最具体的第二个原因。 < P>这是我最终提出的。
class DB {
protected static $_dbh;
const HOST = 'localhost';
const DATABASE = 'dbname';
const USERNAME = 'usname';
const PASSWORD = 'passwo';
private function __construct() { }
public static function get_db_connection() {
if(!isset(self::$_dbh)) {
self::$_dbh = new PDO('mysql:host='.self::HOST.';dbname='.self::DATABASE,self::USERNAME,self::PASSWORD);
self::$_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$_dbh;
}
}
应用单例模式和静态方法调用,我可以轻松访问数据库对象,而无需通过类构造函数传递数据库对象
要在类范围内或类范围外调用数据库对象,我只需调用一行代码
DB::get_DB_connection()代码>
这听起来更可行,不是吗?:) 您可以尝试以下方法:
$GLOBALS['dbh'];
function get_db_connection(){
if(isset($GLOBALS['db_conn']) && get_class($GLOBALS['db_conn']) == 'PDO'){
return $GLOBALS['db_conn'];
}else{
$conn = new PDO(/* parameters */);
$GLOBALS['db_conn'] = &$conn;
return $conn;
}
}
function cnn() {
static $pdo;
if(!isset($pdo)) {
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
$pdo->setAttribute(PDO::ATTR_TIMEOUT, 30);
$pdo->setAttribute(PDO::ATTR_PERSISTENT, true);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
return $pdo;
} else {
return $pdo;
}
}
之后,您可以调用所需的任何查询:
echo cnn()->query('SELECT firstname FROM user WHERE id=4;')->fetch(PDO::FETCH_COLUMN)
第二个查询(对象被重用)
我已经读过很多遍了,在PHP中,使用全局变量是一个坏主意,不知道为什么。@ IbHimiZaar MARAR,它们在C++中有相同的说法,或者支持全局的任何其他语言。你们可以在互联网上搜索,看到各种各样的原因。但是如果是一个小程序,他们中的许多人都支持globals,或者避免多次传递相同的变量(来自维基百科)。所以我认为在有限的范围内使用globals是可以的。在当前状态下,您已经将$dbh声明为全局,因为它在任何函数或类之外,所以为什么不使用它并简化您的生活。您可能正在考虑某种单例系统,但是我想说为什么要为这么简单的事情增加这么多的复杂性。@dansihgoel这个想法是一次创建一个数据库对象并多次重复使用它,我同意全局变量在这里起到了解救作用,但对我来说,它就像是对某个问题的破解或临时修复,我总是避免在我的应用程序中使用全局变量,事实上我从未使用过它。我找到了一个使用单例模式的解决方案,而不是按照您的方式来做。相信我,这比你的解决方案更简单:)你的代码中有一个小错误<代码>!isset($\u胸径)
应该是!isset(self:$\u dbh)
。但这确实是一个很好的解决方案,我甚至可能在未来的项目中使用它。