思考PHP语言三:异常处理
【概述】
异常处理是指在语言中能够使程序按照一种标准的方法对于某些运行时错误和其他程序所检测到的异常事件做出反应。异常发生的时间是不可以确定的,如果一种语言不包括异常处理机制,这就会给语言带来额外的复杂性。
一般来说,对于异常的处理有三种方案:
1、将一个额外的参数作为状态变量,通过标记这个状态值判断是否发生了异常。在C的标准库中许多函数使用返回值作为出错的状态变量。
2、将一个标号参数传给子程序,当异常发生时,通过标号将程序调用跳转到程序中的不同位置
3、将一个异常处理独立出来,作为专门的子程序或类存在。
在基于C的语言中,将异常出现称之为thrown,而不是raise,是因为在标准的C程序库中已经存在一个叫做raise的函数。
在PHP5中使用第3种方式。
【PHP中的异常处理】
在PHP5以后,PHP添加了异常处理模块。PHP的异常处理模块与java有一些类似,异常可被 throw 语句抛出并被 catch 语句捕获。需要进行异常处理的代码都必须放入 try 代码块内,以便捕获可能存在的异常。每一个 try 至少要有一个与之对应的 catch。使用多个 catch 可以捕获不同的类所产生的异常(嗯,这里没有throws子句)。当 try 代码块不再抛出异常或者找不到 catch 能匹配所抛出的异常时,PHP 代码就会在跳转到最后一个 catch 的后面继续执行。所以在安排catch的顺序时,需要将详细或子类的异常类放到前面。在有一些情况下,不管try子句是否抛出异常,也不管是否捕获了异常,程序都要执行一个过程,此时我们就需要finally子句,只是在PHP中并没有finally子句(HOHO)。
一个异常的简单示例:
1 2 3 4 5 | try { throw new Exception("error msg"); }catch(Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } |
PHP提供了Exception类,以及在SPL中提供了一些内置的异常类,我们可以通过继承Exception类而实现属于自己的异常类。在一个面向对象系统的设计中我们需要考虑关于错误的处理情况,是以PHP的内部错误报告,还是以异常的方式给出,此时我们需要规划一套专属于我们系统的异常子系统。并且对于PHP的内部错误报告我们可以使用ErrorException进行转换,如下所示帮助文档中的代码:
1 2 3 4 5 6 7 | function exception_error_handler($errno, $errstr, $errfile, $errline ) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } set_error_handler("exception_error_handler"); /* Trigger exception */ strpos(); |
【断言】
断言常常被用于防错性的程序设计。在一个程序中可以有多条断言,以便确保程序计算的正确性。
PHP提供了assert函数,当执行到此函数时,如果条件为真,则什么都不执行,如果条件为假,则警告并中断程序: Warning: assert() [function.assert]: Assertion failed
经常我们会用echo或die来调试我们的程序,在调试完后我们需要删除相关调试代码。使用assert语句可以在出现问题时将程序调用,而不需要在后面将这些断言删除,这样可以节省删除操作并且在以后的维护过程中也可以重用这些语句,这里就有点测试的感觉了。
当然,我们也可以将断言和异常一起使用,如下所示代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /** * 断言回调函数,抛出异常 */ function assert_callcack() { throw new Exception("msg"); } // Set our assert options assert_options(ASSERT_ACTIVE, true); assert_options(ASSERT_BAIL, true); assert_options(ASSERT_WARNING, true); // 必须为true assert_options(ASSERT_CALLBACK, 'assert_callcack'); /* 触发一个断言*/ assert(0); echo 'Never reached'; |
断言和异常的结合处在于断言的回调函数,只是需要注意的是:assert_options(ASSERT_WARNING, true);
因为断言的错误级别为warning。
在项目中很多RD都喜欢没事就直接throw new Exception,而在调用的时候又直接catch(Exception $e) 这导致异常出现是总是无法定位和管理. 不知道pan有没有这方面的经验分享呢.
@reeze 对于这样的情况,我觉得可以就某些模块就功能点写异常类,在显示异常时将代码的相关信息,如异常所在行,或当前代码等展示出来。