题
我想采用一项旨在在所有我未来的网络应用程序.目前(使用什么我学到从所以迄今为止),我有什么在我的网站,以处理的数据库连接是一个单独的类是这样的:
class DB {
private static $instance = NULL;
private static $dsn = "mysql:host=localhost;dbname=mydatabase;";
private static $db_user = 'root';
private static $db_pass = '0O0ooIl1';
private function __construct()
{
}
private function __clone()
{
}
public static function getInstance() {
if (!self::$instance)
{
self::$instance = new PDO(self::$dsn, self::$db_user, self::$db_pass);
self::$instance-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$instance;
}
}
和另一个文件(文件functions.php)与内容的特定功能看就像这个:
function get_recent_activities ()
{
try
{
$db = DB::getInstance();
// --prepare and execute query here, fetch the result--
return $my_list_of_recent_activities;
}
catch (PDOException $e)
{
return "some fail-messages";
}
}
...
意思是我必须重复 try .. catch
一部分,在所有的职能。
我的问题是:
- 我应该怎么做,更有效率吗?(eg.不必重复
try..catch
在所有职能,但仍然能够返回不同的"失败的消息"每一) - 是的这已经是一个良好做法?我还是新的,在公设辩护人以及面向对象(仍然有很多需要学习),因此(现在),我真的不能看到的任何缺点或事情,可以改善在那里。
我很抱歉如果这似乎不清楚或过长。在此先感谢。
解决方案
您的实施很好,并且它在大多数情况下都能很好地工作。
没有必要将每个查询放在try / catch块中,事实上在大多数情况下你实际上并不想这样做。这样做的原因是,如果查询生成异常,则是语法错误或数据库问题等致命问题的结果,并且这些问题不是您应该对每个查询进行说明的问题。
例如:
try {
$rs = $db->prepare('SELECT * FROM foo');
$rs->execute();
$foo = $rs->fetchAll();
} catch (Exception $e) {
die("Oh noes! There's an error in the query!");
}
此处的查询将正常工作或根本不工作。它根本不起作用的情况不应该在生产系统上有任何规律性,因此它们不是你应该在这里检查的条件。这样做实际上会适得其反,因为您的用户会收到永远不会改变的错误,并且您不会收到提醒您解决问题的异常消息。
相反,只需写下:
$rs = $db->prepare('SELECT * FROM foo');
$rs->execute();
$foo = $rs->fetchAll();
通常,您唯一想要捕获和处理查询异常的时间是在查询失败时要执行其他操作的时间。例如:
// We're handling a file upload here.
try {
$rs = $db->prepare('INSERT INTO files (fileID, filename) VALUES (?, ?)');
$rs->execute(array(1234, '/var/tmp/file1234.txt'));
} catch (Exception $e) {
unlink('/var/tmp/file1234.txt');
throw $e;
}
您需要编写一个简单的异常处理程序,记录或通知您生产环境中发生的数据库错误,并向用户显示友好的错误消息,而不是异常跟踪。有关的信息,请参见 http://www.php.net/set-exception-handler 怎么做。
其他提示
一对夫妇的事项在这里是:
- 这些代码被写入采取几个遗留问题虑到诸如数据库中记录和数据库的配置管理。
- 我强烈建议你看看一个现有的解决方案之前,建立你自己的。很多人认为自己当他们开始他们不想使用现有的构架或图书馆,因为他们太大,需要太多的时间来学习等等, 但是,后一个这些人我不能状态的强调不够,我离开我自定义的框架和包装类移动到了一个框架。我找到动Zend但也有一些优秀的选择。
哦,我应该指出的是,这一点说明了如何可以换一个单一的功能处理所有的例外处理您的查询。我不写尝试抓住块几乎任何其他地方,因为现在的叠的跟踪查询,给我所有的信息,我需要调试的问题和解决它。
这是我目前的公设辩护人的包装类的执行情况:
class DB extends PDO
{
// Allows implementation of the singleton pattern -- ndg 5/24/2008
private static $instance;
// Public static variables for configuring the DB class for a particular database -- ndg 6/16/2008
public static $error_table;
public static $host_name;
public static $db_name;
public static $username;
public static $password;
public static $driver_options;
public static $db_config_path;
function __construct($dsn="", $username="", $password="", $driver_options=array())
{
if(isset(self::$db_config_path))
{
try
{
if(!require_once self::$db_config_path)
{
throw new error('Failed to require file: ' . self::$db_config_path);
}
}
catch(error $e)
{
$e->emailAdmin();
}
}
elseif(isset($_ENV['DB']))
{
self::$db_config_path = 'config.db.php';
try
{
if(!require_once self::$db_config_path)
{
throw new error('Failed to require file: ' . self::$db_config_path);
}
}
catch(error $e)
{
$e->emailAdmin();
}
}
parent::__construct("mysql:host=" . self::$host_name . ";dbname=" .self::$db_name, self::$username, self::$password, self::$driver_options);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('QueryStatement', array($this)));
if(!isset(self::$error_table))
{
self::$error_table = 'errorlog_rtab';
}
}
/**
* Return a DB Connection Object
*
* @return DB
*/
public static function connect()
{
// New PDO Connection to be used in NEW development and MAINTENANCE development
try
{
if(!isset(self::$instance))
{
if(!self::$instance = new DB())
{
throw new error('PDO DB Connection failed with error: ' . self::errorInfo());
}
}
return self::$instance;
}
catch(error $e)
{
$e->printErrMsg();
}
}
/**
* Returns a QueryBuilder object which can be used to build dynamic queries
*
* @return QueryBuilder
*
*/
public function createQuery()
{
return new QueryBuilder();
}
public function executeStatement($statement, $params = null, $FETCH_MODE = null)
{
if($FETCH_MODE == 'scalar')
{
return $this->executeScalar($statement, $params);
}
try {
try {
if(!empty($params))
{
$stmt = $this->prepare($statement);
$stmt->execute($params);
}
else
{
$stmt = $this->query($statement);
}
}
catch(PDOException $pdo_error)
{
throw new error("Failed to execute query:\n" . $statement . "\nUsing Parameters:\n" . print_r($params, true) . "\nWith Error:\n" . $pdo_error->getMessage());
}
}
catch(error $e)
{
$this->logDBError($e);
$e->emailAdmin();
return false;
}
try
{
if($FETCH_MODE == 'all')
{
$tmp = $stmt->fetchAll();
}
elseif($FETCH_MODE == 'column')
{
$arr = $stmt->fetchAll();
foreach($arr as $key => $val)
{
foreach($val as $var => $value)
{
$tmp[] = $value;
}
}
}
elseif($FETCH_MODE == 'row')
{
$tmp = $stmt->fetch();
}
elseif(empty($FETCH_MODE))
{
return true;
}
}
catch(PDOException $pdoError)
{
return true;
}
$stmt->closeCursor();
return $tmp;
}
public function executeScalar($statement, $params = null)
{
$stmt = $this->prepare($statement);
if(!empty($this->bound_params) && empty($params))
{
$params = $this->bound_params;
}
try {
try {
if(!empty($params))
{
$stmt->execute($params);
}
else
{
$stmt = $this->query($statement);
}
}
catch(PDOException $pdo_error)
{
throw new error("Failed to execute query:\n" . $statement . "\nUsing Parameters:\n" . print_r($params, true) . "\nWith Error:\n" . $pdo_error->getMessage());
}
}
catch(error $e)
{
$this->logDBError($e);
$e->emailAdmin();
}
$count = $stmt->fetchColumn();
$stmt->closeCursor();
//echo $count;
return $count;
}
protected function logDBError($e)
{
$error = $e->getErrorReport();
$sql = "
INSERT INTO " . self::$error_table . " (message, time_date)
VALUES (:error, NOW())";
$this->executeStatement($sql, array(':error' => $error));
}
}
class QueryStatement extends PDOStatement
{
public $conn;
protected function __construct()
{
$this->conn = DB::connect();
$this->setFetchMode(PDO::FETCH_ASSOC);
}
public function execute($bound_params = null)
{
return parent::execute($bound_params);
}
}
不隶属于 StackOverflow