我有一个正在开发的应用程序,它使用数据库作为其功能的子集。在开发过程中,我们对数据库不可用的期望高于正常情况。一旦启动,即使出现数据库中断,我们仍然希望应用程序的主体能够正常工作。
我的所有面向数据库的类都扩展了一个基类,该基类授予它们数据库访问权限,但在具体的类中,有一些方法直接执行selects
(意味着不通过基类方法)。
除了用if
语句包装每个数据库调用之外,当数据库不可用时,我如何优雅地降低功能?
编辑
该应用程序正常失败将显示"服务不可用"消息,并阻止类尝试访问数据库(这将引发错误)。
IMHO这属于一般错误和异常处理的更广泛范围。
一些介绍
数据库本质上是代码中的全局变量输入。如果它不可用,这就是意外的"特殊"条件的定义;它应该导致异常。当然,您明确询问了如何处理"没有将每个数据库调用包装在if语句中"的情况。在try/catch
块中包装每个DB操作基本上与在if
语句中包装每个操作相同。
此外,如果无法连接,mysql_connect
函数除了返回FALSE
之外,还会引发PHP错误。您确实应该使用PDO
而不是mysql恐龙,但这完全是另一个主题。希望您没有使用错误抑制运算符@
或不报告E_WARNING
错误来避免这种情况。
那么如何处理
就我个人而言,我与PHP中的错误处理无关。您应该使用set_error_handler
docs定义一个自定义错误处理程序函数,该函数对任何PHP错误抛出异常,并处理异常而不是错误。
当您以这种方式设置错误处理策略时,就可以简单地包装任何可能导致问题或意外抛出try
块的功能,并处理catch
块中的意外事件。
既然您说过,"所有面向数据库的类都扩展了一个基类,该基类授予它们数据库访问权限,"我建议在基类中添加一个简单的布尔属性,作为数据库连接是否失败的标志。然后,只需在每次尝试查询数据库之前检查标志的值。如果你在类中正确地传递了数据库实例(并且没有破坏引用),那么它们在需要时都可以访问相同的属性
如果数据库连接失败,您只需在try块中设置假设的$dbConn->connError = TRUE;
标志。
总之,虽然如何构建实际代码的具体细节取决于您正在做的事情,但使用异常来处理错误条件是IMHO最稳健的方法。
AOP有可能吗?这可以允许您编写截取连接到DB的任何代码部分的代码,并插入错误处理代码。
http://code.google.com/p/php-aop/
我认为在项目中改造我的解决方案并不容易,但我是这样做的:
当我希望在应用程序中将故障识别为关键故障时,我会使用Exceptions。在我的错误处理程序中,我有一些逻辑来确定异常是否与类似4xx的http状态代码匹配,如果不是,则生成一个通用的500状态代码。
非关键故障由使用自定义结果类的破坏性较小的机制捕获。它的基本结构类似于Exception,因为code
和message
是作为构造函数参数传递的。此外,结果对象可以作为可选参数传递。
Result类如下所示:
class Result
{
/**
* @var int
*/
protected $resultCode;
/**
* @var string
*/
protected $resultMessage;
/**
* @var mixed
*/
protected $resultObject;
/**
* Inject object values on construction.
*
* @param int $code
* @param string $message
* @param mixed $result
*/
public function __construct($code = 0, $message = null, $result = null)
{
$this->resultCode = intval($code);
$this->resultMessage = (string) $message;
$this->resultObject = $result;
}
/**
* Returns true when result is considered a success, determined by the
* resultCode, otherwise false.
*
* @return bool
*/
public function isSuccess()
{
if ($this->resultCode > 0) {
return true;
}
return false;
}
/**
* Returns true when result is considered an error, determined by the
* resultCode, otherwise false.
*
* @return bool
*/
public function isError()
{
if ($this->resultCode < 1) {
return true;
}
return false;
}
/**
* Returns the result message.
*
* @return string
*/
public function getMessage()
{
return $this->resultMessage;
}
/**
* Returns the actual result object.
*
* @return mixed
*/
public function getResult()
{
return $this->resultObject;
}
}
只需要结果代码。如果代码>0,则结果被视为成功,否则被视为错误。结果对象可以是实际结果(如果成功),例如查询中的行或行集,或者(如果错误)输入或输入的相关部分,例如您要查找的行id。
由于这个结果类不会触发errorHandler,因此MVC应用程序被信任来处理错误。通过抛出异常,或者通过显示作为结果对象传递的消息或其他内容来优雅地对失败结果作出反应。
如果我将这个结果传递给我的视图,我可以对$result->isSuccess()
是真是假做出反应,并通过$result->getResult()
获得实际结果,或者通过$result->getMessage()
显示错误消息。