核心要点
Exception
等同于说存在“问题”,而代码无法知道发生了什么。相反,应始终抛出自定义异常,以告知调用代码当前情况,从而对发生的情况进行细粒度控制。PHP 5 引入了异常处理机制,这是一种特殊的类,可以抛出和捕获(与引发的错误相反),表示意外事件。与错误不同,异常旨在由调用代码处理,并沿执行链向上冒泡,直到被捕获。一旦抛出异常,当前作用域中的代码将停止执行(因此,throw
语句之后的任何行都不会执行),控制权将返回到第一个匹配的异常处理程序(捕获块、配置的异常处理程序或语言提供的异常处理程序)。只有当异常被捕获时,代码执行才会从那里继续。本文并非旨在从入门级别讲解异常,而是就如何更好地使用异常提供一些建议。如果您以前从未使用过异常,您可能需要查阅 PHP 手册,或阅读我的朋友们编写的《PHP Master:编写尖端代码》一书,该书出色地讲解了编写现代、合理的 PHP 代码所需的一切知识。
错误并非异常
您可能已经了解了异常,但您可能想知道 PHP 错误和(自定义)异常之间的区别。逻辑实际上很简单:错误是不可恢复的,发生在主执行循环中,并且表示环境的稳定性。例如,如果您尝试将标量值作为数组访问而引发了 E_NOTICE
,则表示您的代码存在问题。无法保证继续执行是安全的。无法在执行期间纠正该条件。如果由于解析器发现意外的 T_IF
而引发了 E_PARSE
,那么您就会明白这如何影响事物的稳定性。另一方面,异常是可恢复的,可以(并且通常会)发生在主执行循环之外,并且不会指示系统的稳定性。它是一个组件说:“我无法使用给定的输入完成您的请求,因此您可以随意处理该信息。”如果库抛出 LengthException
,则表示传递的值过长或过短,因此它无法使用当前值完成给定的指令。这并不意味着您的环境不稳定,只是意味着您的代码必须通过填充或截断来调整值的长度。您的代码可以捕获此异常,更新值,然后重试。
并非所有异常都是例外情况
这是最难回答的问题之一:究竟什么情况需要抛出异常?当然,您的异常必须符合上一段中的三个规则。当遇到损坏的内存时抛出异常是非常糟糕的做法。您的代码应该改为引发错误,以便 PHP 能够尽快中止,因为事实证明,环境不安全以继续执行。但是,即使错误是不必要的,也不是所有非成功的情况都需要异常。也就是说:并非所有不成功的情况都是例外情况。“异常”这个词指的是不属于普通操作或标准的动作,一个异常,与正常和预期情况有所偏差。一位前同事曾经在晚餐时告诉我他们公司使用的 XML/RPC 服务的设计情况,该服务是所有面向公众的操作的支柱。架构师随后了解了异常以及它们在指示非成功状态方面的便利性。该支柱除了其他功能外,还提供了单点登录功能。Web 应用程序不会直接访问数据库,而是查询 XML/RPC 服务,然后该服务将根据为所有 Web 应用程序提供服务的集中式数据存储进行回复。当提供有效的凭据时,将返回成功状态。当出现问题时,将抛出异常,并显示一条消息,指示失败的原因。易于捕获,您可以以醒目的、闪亮的错误消息向用户显示该消息。但是,用户提供不正确的用户名和/或密码真的偏离了预期吗?在我的项目中,我处理的用户并不完美,他们会打错字或忘记事情。获取不正确的凭据是非常常见的,甚至比有效的凭据更常见。验证凭据是登录系统的预期行为,因此在这种情况下,XML/RPC 服务应返回一个状态,指示验证的成功与否。尽管凭据未通过,但验证过程本身仍然成功执行。如果验证过程未正确执行,则说明还有其他问题。也许数据存储不可访问,或者其他什么原因。登录系统无法连接到其数据存储的情况非常不常见,因为它无法在没有数据存储的情况下运行。因此,这需要抛出异常。注意:有些人可能会争辩说,登录系统无法连接到数据存储是环境不稳定的标志,因此应该引发错误。但是,登录系统不负责为数据存储引发错误。相反,如果数据存储连接器/包装器认为有必要,则应引发错误。一般来说,您可以将异常视为开发人员必须介入、查看情况并进行处理的情况。发生异常场景的代码本身无法做到这一点。这可能是开发人员已经查看过代码,并且他们处理它的方式是在它发生时让它发生。不要开始将所有异常都通过邮件发送给网络运营中心;他们不会感激的!处理您可以并且应该处理的内容,并且只有在确实无法继续执行时才抛出异常。
“问题”
几年前,当我徒步旅行穿过欧洲时,我在希腊的一个火车站偶然发现了一个令人难忘的景象。其中一个储物柜区域看起来像炸弹爆炸了一样,门散落在地上,一半挂在铰链上,或者被砸碎了。我后来了解到他们正在拆除储物柜区域,但值得注意的是,他们是如何向客户传达此区域已停用的。在中央部分贴了很多胶带,上面贴着一张纸,上面写着“问题”两个字。从技术上讲,这是完全正确的。储物柜显然出了问题,并且情况已通过向客户传达来处理。您可能会觉得它很有趣,但实际上您在代码中经常会看到这种情况。如果您只抛出 Exception
,那么您基本上就是在说“问题”,而代码无法知道发生了什么。虽然 Exception
是每个异常的基类,但您可以使用您自己的类型扩展它。在 SPL 库中可以找到更广泛的异常集合,但这远非极限。查看 Zend Framework 或 Symfony 等主要的 PHP 框架,您会发现它们几乎为每种不同的情况都使用自定义异常。编写所有这些文件以便可以动态加载它们并维护所有不同类型有点麻烦,但这为框架和该框架的使用者提供了对发生情况的细粒度控制。如果只抛出 Exception
,那么您只能确定某些事情不对劲,您不妨放弃。这意味着您使用异常的方式就像它们是错误一样,将捕获块用作静默操作符,并且只是放弃了有人可以以某种方式纠正这种情况的希望。
全局捕获
如果使用非自定义异常和捕获所有可能的异常是一个坏主意,那么为什么语言甚至允许这样做呢?始终使用和捕获特定异常的规则有一个例外,那就是全局捕获规则。全局捕获块是最高级别的捕获块,必须捕获所有冒泡到该级别的异常。PHP 本身包含一个(您是否见过“致命错误:未捕获的异常在……”消息?),但您可以使用自定义处理程序覆盖它以作为后备。您可以使用 set_exception_handler()
函数设置此处理程序,因此您可以随意这样做,然后向您的 PHPMD 规则集中添加一条规则,禁止类似于“catch (Exception $e) {
”之类的行。这是唯一一个应该在生产代码中找到的一般异常处理程序的原因,它捕获尚未捕获的 Exception
类的每个实例。其他处理程序必须是特定的,并且仅限于它知道如何处理和负责的异常。在这里谨慎行事,让一个可处理的异常冒泡一次(然后在代码中修复它)肯定比捕获太多并充当静默操作符要好得多。
总结
总而言之,只有当您的代码无法使用给定的输入完成请求的指令时才抛出异常,始终抛出自定义异常,该异常实际上会告诉调用代码当前情况,并且如果您调用其他代码,则只捕获您可以并且应该处理的异常。这将使您的组件更少像黑盒(自定义异常),并减少集成您的组件的开发人员必须更改您的代码的可能性(不要捕获您不应该捕获的异常)。我们总是告诉我们的客户/管理人员要具体,但我们也应该具体!
(图片来自 Fotolia)
关于 PHP 异常处理的常见问题
PHP 异常处理是一种强大的机制,允许开发人员管理程序执行期间可能发生的错误和异常情况。它提供了一种将控制从程序的一个部分转移到另一个部分的方法。PHP 异常处理用于在发生指定错误时更改代码执行的正常流程。这可以使代码更易于阅读和管理,因为它将错误处理代码与主程序逻辑分开。
在 PHP 中,try-catch 块用于处理异常。try 块包含可能抛出异常的代码,而 catch 块包含如果 try 块中抛出异常将执行的代码。如果 try 块中抛出异常,则脚本停止运行,控制权将传递给与抛出的异常类型匹配的第一个 catch 块。
PHP 异常处理中的 finally 块用于确保始终执行一段代码,无论是否抛出异常。这对于清理活动(例如关闭文件或数据库连接)非常有用,无论操作成功还是失败都应执行这些活动。
在 PHP 中,您可以通过扩展内置的 Exception 类来创建自定义异常。这允许您向异常添加自定义功能,或创建特定于应用程序域的异常。要创建自定义异常,您可以定义一个扩展 Exception 的新类,然后添加所需的任何自定义方法或属性。
在 PHP 中,错误是一个严重的问题,会阻止脚本运行,而异常是一个改变正常执行流程的条件。错误通常是由语法错误或调用未定义函数等原因引起的。另一方面,异常通常用于处理对程序并非致命但需要特殊处理的条件。
在 PHP 中,您可以使用多个 catch 块来处理多个异常。每个 catch 块处理特定类型的异常。当抛出异常时,将按代码中出现的顺序检查 catch 块。将执行第一个能够处理抛出的异常类型的 catch 块。
是的,您可以在 PHP 中重新抛出异常。如果您想以某种方式处理异常,但又想让更高级别的异常处理程序捕获它,这将非常有用。要重新抛出异常,只需在 catch 块中使用 throw 语句即可。
在 PHP 中,您可以通过在 catch 块中使用 error_log 函数来记录异常。这允许您将有关异常的信息(包括其消息和堆栈跟踪)记录到指定的日志文件中。
PDOException 是一种异常,当 PDO 操作中发生错误时会抛出该异常。PDO(PHP 数据对象)是一个数据库抽象层,它为访问 PHP 中的数据库提供一致的接口。PDOException 提供有关错误的信息,包括 SQLSTATE 错误代码和数据库驱动程序的错误消息。
在 PHP 中,您可以通过定义自定义异常处理程序函数,然后使用 set_exception_handler 函数将其设置为默认异常处理程序来处理未捕获的异常。每当抛出未被 try-catch 块捕获的异常时,都会调用此函数。
以上是PHP主|例外的详细内容。更多信息请关注PHP中文网其他相关文章!