因此,我开始使用this tutorial作为PDO的简介。到目前为止,我只处理过基本的mysql_*
类型查询。
我注意到,在整个教程中,connect -> do action -> disconnect
模式都是重复的,只有do action
部分会发生变化。
在现实世界中,通过创建一个可以传递查询的函数来消除重复是不是一个好主意?
例如:
用于处理查询的函数:
<?php
function databaseDo($action) {
$db_hostname = 'localhost';
$db_username = 'root';
$db_password = 'root';
try {
// Establish DB connection
$dbh = new PDO("mysql:host=$hostname;dbname=mysql",
$db_username, $db_password);
echo 'Connected to database';
// Do something
$action($dbh); // <- here goes whatever action we wish to perform
// Close connection
$dbh = null;
}
catch(PDOException $e) {
echo $e->getMessage();
}
?>
然后,假设我想要执行PDO教程的第一个示例中的操作,我会这样设置它:
<?php
// Define action
$insert = function($dbh) {
$query = "INSERT INTO animals(animal_type, animal_name)
VALUES ('kiwi', 'troy')";
$exec = $dbh->exec($query);
echo $exec;
};
// Perform action
databaseDo($insert);
?>
$dbh的范围
我使用$dbh作为参数。这是将变量传递给这样的函数而不使其成为全局变量的正确方式吗?
发布于 2012-09-15 03:18:03
是的,这是一个很好的想法,一个建议是创建一个使用单例模式的数据库助手类。就像这样
abstract class DB
{
protected static $instance;
protected $db;
protected static $host = 'host';
protected static $user = 'user';
protected static $pass = 'pass';
protected static $database;
public static function getInstance()
{
if (!isset(self::$instance)) self::$instance = new static();
return self::$instance;
}
public static function doStatement($statement, array $parameters)
{
$handler = self::sql()->prepare($statement);
$handler->closeCursor();
$handler->execute($parameters);
return $handler;
}
protected function __construct()
{
$this->db = new PDO(sprintf('mysql:host=%s;dbname=%s', static::$host, static::$database), static::$user, static::$pass);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
}
public static function db()
{
return static::getInstance()->db;
}
}
class Main extends DB
{
protected static $database = 'db';
}
使用它
$db = Main::getInstance();
$results = $db::doStatement('SELECT * FROM table WHERE id = :id', array(':id' => 5));
现在这只是非常基本的,还需要添加更多(异常处理,更多/更好的助手方法等),但我已经在许多项目中使用了类似的东西。
发布于 2012-09-15 04:39:02
虽然避免重复(DRY)是一个应该始终考虑到您的编码决策的原则,但它应该在不违反另一个重要原则的情况下实现,即关注点分离(SoC,另请参阅SRP)。您的示例databaseDo($action)有两个用途:(1)实例化一个数据库连接,(2)执行一个查询。
现在,你可能会说,‘是的!这正是我想要的!一举两得!’,你这样说的理由是可以理解的。然而,混合职责可能会变得有问题,因为当您必须更改处理一个职责的方式时,您很可能也必须更改处理另一个职责的方式。
想象一下,在将来的某个时刻,您需要支持两个数据库连接,而不是只支持一个。假设两个数据库中的一个支持表上的事务,而另一个不支持。您的databaseDo()函数首先必须协商连接到哪个数据库,然后,为了安全地执行“do”操作,将需要一些事务支持测试。它看起来像这样:
$context = 'production'; // but it could equally be 'development'
function databaseDo($action) {
$db_hostname = ($context == 'production') ? 'http://remotehost.com' : 'localhost';
$db_username = ($context == 'production') ? 'apache' : 'root';
$pass = ($context == 'production') ? 'productionpassword' : 'developmentpassword';
try {
$dbh = new PDO("mysql:host=$db_hostname;dbname=mysql", $db_username, $db_password);
echo 'Connected to database';
if($context == 'production') {
// ... some complicated logic to determine whether the production db
// will support your query, then execute it if so, exit if not ...
}
if($context == 'development') {
// ... some more complicated logic for testing and querying the
// development db ...
}
$dbh = null;
} catch(PDOException $e) {
echo $e->getMessage();
}
}
处理一个职责的额外需求将增加处理第二个职责的复杂性,并且此功能将变得越来越难以维护。
在这种情况下,更好的DRY方法是在一个组件中处理数据库连接管理,例如在上下文感知的单例类实例中(一种常见的方法),而在另一个组件中处理查询处理。因此,您的查询函数不一定要因为数据库连接处理的更改而更改。您提到的教程包含instructions for creating and using such a singleton instance。
https://stackoverflow.com/questions/12434093
复制相似问题