如何通过重用使数据库对象更有效

时间:2011-09-23 04:04:32

标签: php design-patterns singleton

我对如何处理重用数据库对象和配置变量或应用程序全局常量的逻辑感到困惑。

我一直在做的方式是,我在config.php目录中创建了一个Config文件并声明所有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';
}

并且在index.php文件中,我将包含此文件一次,并在每个对象中重复使用它。

我的index.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 = new User($dbh);

一切正常,但问题是每个类我必须通过构造函数传递数据库句柄对象并在类中重用它对我来说有点难看。如果我想使用包含静态方法和属性的类来保存要从数据库中检索的应用程序设置,这种方法对我来说会产生问题。我的要求就是这样。

我想使用单一模式创建一个静态方法,该方法将保存要在整个应用程序中使用的数据库对象,而不需要每次通过构造函数为每个类传递$dbh对象。我对如何处理这个问题非常困惑。

谢谢

3 个答案:

答案 0 :(得分:1)

我有一个类似的设计模式,我将连接连接并存储在全局中。

您不需要将数据库变量传递给每个类,因为它是全局的。

你可以在任何地方使用它:

$GLOBALS['dbh'];

为了隐藏这个,我实际创建了一个名为get_db_connection()的函数,它首先检查$GLOBALS数组中是否存在有效连接然后返回它。此外,如果那里没有有效连接,它会创建一个新连接,将其存储在$ GLOBALS中并返回它。

我需要在任何地方手动实例化连接,它会在第一次调用get_db_connection时自动创建,随后随处可用。

get_db_connection函数看起来像这样:

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;
    }
}

支持全球的辩护
我认为这是对全局变量的可原谅的用法,原因如下:

  • 变量$ dbh已经是全局变量,因为它不在函数内部 或者是一堂课。
  • 您无法直接访问全球任何地方 你的程序,但只能通过一个函数get_db_connection 所以任何人都可以改变全球价值的问题不是 这里。
  • 解决这个问题的唯一方法是使用Singleton,它可能是 这样一个简单问题是不必要的。

其中我认为第二个原因是最具体的。

答案 1 :(得分:0)

这是我最终想出来的。

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();

这听起来更可行不是吗? :)

答案 2 :(得分:0)

您可以尝试这样的事情:

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)

第二个查询(对象被重用)

echo cnn()->query('SELECT title FROM news WHERE id=516;')->fetch(PDO::FETCH_COLUMN)