应该将捕获的异常直接重新抛出,还是将它们包装在新的异常周围?

也就是说,我应该这样做:

try {

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

} catch (Exception $e) {

throw $e;

}

或这个:

try {

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

} catch (Exception $e) {

throw new Exception("Exception Message", 1, $e);

}

如果您的答案是直接抛出,请建议使用异常链接,但我无法理解我们使用异常链接的实际情况。

除非您打算做一些有意义的事情,否则不要捕获异常。

"有意义的事情"可能是其中之一:

处理异常

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

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"。这使Component的使用者可以捕获预期类型的??异常,同时还允许调试代码访问所有(与实现有关的)详细信息。

提供更丰富的上下文(带有异常链接)

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

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

}

并导致捕获到"无法创建目标目录"异常错误,您将有权利混淆。将此"核心"异常包装在提供上下文的其他异常层中,将使错误更易于处理("创建配置文件复制失败"->"文件复制操作失败"->"无法创建目标目录")。

阿门。忘记我的答案,请阅读Jons。

我仅同意最后两个原因:1 /处理异常:您不应该在此级别执行此操作; 2 /日志记录或清理:最后使用并将异常记录在数据层上方

@remi:除了PHP不支持finally构造(至少现在还不支持)...就这样了,这意味着我们必须诉诸于这种肮脏的事情...

@remibourgarel:1:这只是一个例子。当然,您不应该在此级别上这样做,但是答案足够长了。 2:正如@ircmaxell所说,PHP中没有finally。

@ircmaxell:对不起,我没有使用php那样的代码,所以我做了一些研究,但是看来我的来源是错误的bugs.php.net/bug.php?id=32100

终于,PHP 5.5现在终于实现了。

不管是否引发异常,都会执行finally块中的代码。请在读取something went wrong, take corrective measures, let exception propagate的finally示例中更改您的注释,以避免混淆。

@wadim:非常令人误解,谢谢。我收拾了

我认为您没有从这里的列表中遗漏是有原因的-在您捕获到异常并有机会对其进行检查之前,您可能无法确定是否可以处理异常。例如,使用错误代码(并且有不计其数的错误代码)的低级API的包装器可能只有一个异常类,该异常类会抛出任何错误的实例,并带有一个error_code属性,该属性可以进行检查以获取基本错误代码。如果您仅能够有意义地处理其中一些错误,则您可能想捕获,检查,如果无法处理错误,请重新抛出。

@MarkAmery:在实践中这可能只是个小众市场,但这绝对是一种可能性-它也可能适用于设计不理想的异常抛出API。我不认为它在列表中有自己的位置(我打算对标准技术进行概述),但是要牢记这一点。感谢您的反馈意见!

@JulienPalard:这是我第一次听说此特定错误(我知道Exception构造函数通常很挑剔)。 您能否提供一个示例,其中传入"42"而不是42是一个问题?

@Jon PHP 5.4.38此处用于记录,$ php -r throw new Exception("42","42");给出了PHP Fatal error: Uncaught exception Exception with message 42 in Command line code:1嗡嗡声,多数民众赞成在正常情况下...试图重现另一种方式...

@Jon $ php -r throw new Exception("message","code"); PHP Fatal error: Wrong parameters for Exception([string $exception [, long $code [, Exception $previous = NULL]]]) in Command line code on line 1。 有时在PDOException中发生这种情况,getCode()可以返回包含字母的内容。 通常在MySQL SELECT * FROM unexisting_table上给出42S02。

@Jon因此,答案是否定的,我显然无法提供一个示例,其中传递"42"而不是42是一个问题。

我会赶上Throwable。 Exception和Error都至少从PHP 7中的Throwable继承。

好吧,这都是关于维护抽象的。因此,我建议使用异常链接直接抛出异常。至于为什么,让我解释一下泄漏抽象的概念

假设您正在建立模型。该模型应该从应用程序的其余部分中抽象出所有数据持久性和验证。那么,当您遇到数据库错误时会发生什么呢?如果重新抛出DatabaseQueryException,则表示泄漏了抽象。要了解原因,请考虑一下抽象。您不必关心模型如何存储数据,就可以了。同样,您不必在乎模型的基础系统到底出了什么问题,只是您知道出了什么问题,并且大概知道出了什么问题。

因此,通过抛出DatabaseQueryException,您将泄漏抽象,并要求调用代码了解模型下正在发生的事情的语义。而是创建一个通用ModelStorageException,并将捕获的DatabaseQueryException包装在其中。这样,您的调用代码仍然可以尝试从语义上处理错误,但是,该模型的基础技术无关紧要,因为您仅从该抽象层公开了错误。更好的是,由于您包装了异常,如果异常一直冒出来并需要记录,则可以跟踪引发的根异常(遍历整个链),因此您仍然拥有所需的所有调试信息!

除非您需要进行一些后处理,否则不要简单地捕获并抛出相同的异常。但是像} catch (Exception $e) { throw $e; }这样的块是没有意义的。但是您可以重新包装异常以获取一些明显的抽象收益。

好答案。似乎相当多的人围绕Stack Overflow(基于答案等)使用错误的代码。

恕我直言,捕获异常以将其重新抛出是没有用的。在这种情况下,只是不要捕获它,而是让先前调用的方法对其进行处理(也就是在调用堆栈中位于"上层"的方法)。

如果将其抛出,将捕获到的异常链接到将要抛出的新异常中绝对是一个好习惯,因为它将保留捕获到的异常所包含的信息。但是,仅当您添加一些信息或处理所捕获的异常时,重新抛出它才有用,可能是某些上下文,值,日志记录,释放资源等。

添加一些信息的一种方法是扩展Exception类,使其具有诸如NullParameterException,DatabaseException等的异常。此外,这使开发人员只能捕获他可以处理的某些异常。例如,只能捕获DatabaseException并尝试解决导致Exception的原因,例如重新连接到数据库。

它不是没有用的,有时您需要对抛出异常的函数执行某些操作,然后将其重新抛出以使更高级别的捕获执行其他操作。在我正在从事的一个项目中,有时我们会在操作方法中捕获异常,向用户显示友好通知,然后将其重新抛出,因此代码中更远的try catch块可以再次捕获该错误以将错误记录到一个日志。

因此,正如我所说,您向异常添加了一些信息(显示通知,记录日志)。您不会像在OPs示例中那样将其重新抛出。

好吧,如果您需要关闭资源,但是没有其他信息要添加,则可以将其重新抛出。我同意这不是世界上最干净的东西,但它并不可怕

@ircmaxell同意,已进行编辑以反映出仅当您除了将其扔掉以外不做任何其他事情时它才是无用的

重要的一点是,通过重新抛出该异常,您可以松开该文件和/或行的信息,以了解最初引发异常的位置。因此,通常最好先提出一个新的问题,然后再传递一个旧的问题,就像问题的第二个例子一样。否则,它只会指向catch块,让您猜测实际的问题是什么。

我在这里了解如何处理这种"无用"的情况。发出请求时发生任何错误时,Guzzle都会引发通用异常。可以处理诸如OAuth令牌刷新之类的问题。但是要确定OAuth令牌是否已过期,需要对响应进行更深入的检查。如果发现不是这种情况,则需要重新抛出异常,以便更进一步的处理任何异常。异常可能太广泛了,您不知道是否可以处理它,直到更深入。

您必须了解PHP 5.3中的Exception Best Practices

任何情况下,PHP中的异常处理都不是新功能。在以下链接中,您将看到PHP 5.3中基于异常的两个新功能。第一个是嵌套异常,第二个是由SPL扩展(现在是PHP运行时的核心扩展)提供的一组新的异常类型。这两个新功能均已进入最佳实践手册,应进行详细检查。

http://ralphschindler.com/2010/09/15/exception-best-practices-in-php-5-3

您通常是这样想的。

一个类可能会抛出许多不匹配的异常。因此,您可以为该类或类的类型创建一个异常类并将其抛出。

因此,使用该类的代码仅必须捕获一种类型的异常。

嘿,您能否提供更多详细信息或链接,以便在其中阅读有关此方法的更多信息。

php抛出和捕获异常,关于php:捕获和重新抛出异常的最佳实践是什么?相关推荐

  1. mysql如何抛出错误信息_如何捕获并重新抛出MySQL中的所有错误

    我似乎无法在任何地方找到如何捕获并重新抛出可能发生在过程中的任何错误或警告. 我想要的是执行以下操作的语法: create procedure myProcedure() begin declare ...

  2. java不抛出方法异常,java – 重写方法不会抛出异常

    编译我的代码时遇到问题,我试图让一个类的方法抛出一个个性化的异常,给定一些条件.但在编译时我得到的信息是: Overridden method does not throw exception 这是类 ...

  3. java 异常 过滤器_在过滤器Filter中抛出一个全局异常可以捕获的异常

    1.创建自定义异常 public class TokenException extends RuntimeException { private static final long serialVer ...

  4. Python程序异常处理:try、except、else、finally,捕获指定异常类型、捕获多个异常类型、捕获所有异常类型、捕获异常信息、异常的传递、raise抛出自定义异常

    输入与预期不匹配,触发异常,程序退出: 一.异常处理:使用try.except进行错误处理 为了保证程序运行的稳定性,错误应该被程序捕捉并合理控制 Python使用保留字try和except进行异常处 ...

  5. .NET 指南:捕获并且抛出标准的异常类型

    下列指导方针为 .NET Framework 所提供的一些最常用的异常而描述了最佳的实践.关于 .NET Framework 所提供的完整的异常类列表,请参考:[.NET Framework 类库参考 ...

  6. springBoot 在过滤器中如何捕获抛出的异常并自定义返回信息

    一般springBoot自带的全局异常捕获机制都是在业务层发生的异常来进行捕获的,因为过滤器的执行顺序是在全局异常机制启动之前执行的,所以一旦过滤器中发生异常,全局异常捕获机制无法使用 现在有一个围魏 ...

  7. java抛出数组格式异常,Java中异常

    一.异常的概述 在Java中,把异常信息封装成了一个类.当出现了问题时,就会创建异常类对象并抛出异常相关的信息(如异常出现的位置.原因等). 二.异常的继承体系和错误的区别 1.异常的继承体系 Thr ...

  8. java exception 二次抛出_java – 如何在scheduleWithFixedDelay抛出异常时重新启动计划?...

    你可能应该在一个while(true)循环中包含try块,因为如果第一次运行没有抛出异常,你将退出你的方法,如果第二次调用抛出一个,你将无法捕获它. 我还会在自己的线程中运行递归调用,以避免在事情变坏 ...

  9. java 抛出异常的作用_Java 基础之异常抛出

    Java 基础之异常抛出 Java,基础,异常抛出 在 Java 里,除了对异常的捕获外,你还可以抛出异常,还可以创造异常.抛出异常的作用就是告诉你的调用者,程序出现了不正常的情况了,得不要期望的结果 ...

最新文章

  1. PCL—低层次视觉—点云分割(基于凹凸性)
  2. 图像处理之噪声---椒盐,白噪声,高斯噪声三种不同噪声的区别
  3. excel表格行列显示十字定位_Excel行列十字交叉高亮显示
  4. Oracle的left join中on和where的区别
  5. IOC注解注入View
  6. nyoj-68--三点顺序
  7. python内置类属性_Python内置方法和属性应用:反射和单例(推荐)
  8. [源码和文档分享]C语言实现的基于Huffman哈夫曼编码的数据压缩与解压缩
  9. 受JAAS保护的JAX-RS端点
  10. beoplay耳机序列号查询_BOSE耳机序列号如何查询?
  11. python 怎么将数组转为列表_怎么将视频转为GIF动态图 表情包怎么制作
  12. 《SEO字典》解读meta robots标签
  13. Hadoop入门进阶步步高(三-配置Hadoop
  14. Linq to sql介绍及增、删、改、查
  15. 计算机脚本发生错误,我的电脑开机后显示当前页面的脚本发生错误?
  16. 计算机视觉——图像拼接
  17. 180822 逆向-网鼎杯(2-1)
  18. piaget读法_读音教学 | 这些手表品牌原来是这么念的!
  19. 2023最新织梦CMS高端红酒酒水类网站模板源码+SEO全屏自适应布局
  20. 国货崛起,科技潮流——雷神星驰轮胎

热门文章

  1. 牛客网编程题05--进制转换
  2. django学习----01HelloWorld
  3. C语言嵌入汇编指令(asm)查询系统时间
  4. python 去掉转义字符_python前期准备
  5. vc安装.zip_空间分析:4-1.分词模型hanLP简介与安装
  6. 传统socket的编程实现
  7. vscode修改c 项目_windows 10上使用vscode编译运行和调试C/C++
  8. c语言实现感知器算法,感知器算法(c语言版).doc
  9. java excel添加公式_Java添加、读取Excel公式
  10. OpenShift 之 用CodeReady Workspaces开发Quarkus云原生应用