php重新抛出异常,php – 捕获和重新抛出异常的最佳做法是什么?

你不应该捕获异常,除非你打算做一些有意义的事情。

“有意义”可能是以下之一:

处理异常

最明显的有意义的动作是处理异常,例如。通过显示错误消息并中止操作:

try {

$connect = new CONNECT($db, $user, $password, $driver, $host);

}

catch (Exception $e) {

echo "Error while connecting to database!";

die;

}

记录或部分清理

有时你不知道如何在特定上下文中正确处理异常;也许你缺乏关于“大图片”的信息,但你想要记录失败尽可能接近发生的点。在这种情况下,您可能需要捕获,记录和重新抛出:

try {

$connect = new CONNECT($db, $user, $password, $driver, $host);

}

catch (Exception $e) {

logException($e); // does something

throw $e;

}

相关的场景是,你在正确的地方为失败的操作执行一些清理,但不决定如何在顶层处理失败。在早期的PHP版本中,这将实现为

$connect = new CONNECT($db, $user, $password, $driver, $host);

try {

$connect->insertSomeRecord();

}

catch (Exception $e) {

$connect->disconnect(); // we don't want to keep the connection open anymore

throw $e; // but we also don't know how to respond to the failure

}

PHP 5.5引入了finally关键字,所以对于清理场景,现在有另一种方法来处理。如果清除代码需要运行,不管发生了什么(即错误和成功),现在可以这样做,同时透明地允许任何抛出的异常传播:

$connect = new CONNECT($db, $user, $password, $driver, $host);

try {

$connect->insertSomeRecord();

}

finally {

$connect->disconnect(); // no matter what

}

错误抽象(含异常链接)

第三种情况是,你想在一个更大的伞下逻辑地分组许多可能的故障。逻辑分组的示例:

class ComponentInitException extends Exception {

// public constructors etc as in Exception

}

class Component {

public function __construct() {

try {

$connect = new CONNECT($db, $user, $password, $driver, $host);

}

catch (Exception $e) {

throw new ComponentInitException($e->getMessage(), $e->getCode(), $e);

}

}

}

在这种情况下,您不希望Component的用户知道它是使用数据库连接实现的(也许您希望保持您的选项打开并在将来使用基于文件的存储)。所以你的Component的说明会说“在初始化失败的情况下,会抛出ComponentInitException”。这允许组件的消费者捕获预期类型的​​异常,同时还允许调试代码访问所有(依赖于实现的)细节。

提供更丰富的上下文(使用异常链接)

最后,在某些情况下,您可能希望为异常提供更多的上下文。在这种情况下,将异常包装在另一个异常中是有意义的,其中包含有关在发生错误时尝试执行的操作的更多信息。例如:

class FileOperation {

public static function copyFiles() {

try {

$copier = new FileCopier(); // the constructor may throw

// this may throw if the files do no not exist

$copier->ensureSourceFilesExist();

// this may throw if the directory cannot be created

$copier->createTargetDirectory();

// this may throw if copying a file fails

$copier->performCopy();

}

catch (Exception $e) {

throw new Exception("Could not perform copy operation.", 0, $e);

}

}

}

这种情况类似于上面的(和示例可能不是最好的一个可能出现),但它说明了提供更多的上下文的点:如果抛出异常,它告诉我们文件复制失败。但是为什么会失败呢?此信息在包装的异常(如果示例更复杂,可能有多个级别)中提供。

这样做的价值说明如果你想一个场景,例如。创建UserProfile对象会导致复制文件,因为用户配置文件存储在文件中,并且它支持事务语义:您可以“撤消”更改,因为它们只在配置文件的副本上执行,直到您提交。

在这种情况下,如果你做到了

try {

$profile = UserProfile::getInstance();

}

并且作为结果捕获一个“目标目录无法创建”的异常错误,您将有权被困惑。在提供上下文的其他异常层中包装此“核心”异常将使错误更容易处理(“创建配置文件复制失败” – >“文件复制操作失败” – >“无法创建目标目录” )。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值