在写这篇文章前,我需要说明的是,这里的网站异常系统所使用的是PHP语言来实现的,PHP有自带的异常处理机制,但比起JAVA等一些其它语言来,它的处理机制可能就相对没有那么强大了,但我们这里就不讨论PHP语言与其它语言在关于异常系统处理之间的区别的,这篇文章所主要讨论的是在网站开发为何需要设计异常系统,以及用PHP语言对这个异常系统如何进行设计。
我们知道异常系统主要做的作用就是用于跟踪系统的BUG,并把它修正好,在我们的网站系统当中同样也是相当的重要。
一个网站系统,不可能可以永远的保证它能百分百运行良好,很多时候,也许你在一次不经意间的修改当中便使错误发生,这个错误也许是一个警告性的错误,但因为你把错误屏蔽了,暂时不会影响你的程序运行,但也许也会产生一个致命性的错误,这时即使你把错误给屏蔽了,程序也会戛然而止,用户看到的也是一片大白,更别说做别的操作了。
上面那段我更偏向于程序性的错误,但其实在很多时候,也有其它一些情况,如我们在与用户交互过程中,经常需要有一些提示性的错误,由其是在做一些业务性很强的操作时,我们现在做的广告分析系统,便是这样,操作性的提示超多,那如此多的提示信息,就让它显示于你的逻辑性代码之中,然后如果哪一天你需要进行修改提示时,还得一个一个去查找并修改吗?我想这是谁都不想的,说到了这里,也许也会有很多同学认为,这跟我们的异常处理有什么关系呢,先别急,这些问题就是我下面所需要讲解的。
上面已经提出了两大问题,至于怎么解决这两大问题,我说一下我的处理方法
第一类:程序性的错误,我们可以很明确的知道,PHP的异常系统可能使用捕获的方式来获得,但很多时候,但这样需要加入很多的TRY。。。CATCH语句,对于我这样一个对代码美观性要求比较高的人,我并不喜欢这种方式,而且有一种错误,就算我加入了这类捕获语句,我也捕获不到,这类性的错误,就是Fatal Error,对了,就是致命性的错误,至于为什么捕获不到,我记得网上有一篇文章是专门讲这个的,您可以上网百度或者谷歌一下,我也就不讲了,你只要知道,这类性的错误,使用常规性的办法是捕获不到就行了,那既然捕获不到,那万一真用户在操作过程中程序真遇到了这个问题,那怎么办,用户岂不是既看不到结果也看不到提示了,不错,这时如果你没有一个良好 的异常捕获系统,在这点上的用户体验就会差很多,呵,有些同学可能真急了,觉得讲了这么多废话还是没有讲到具体怎么解决,就快了,我们现在已经知道,程序性的异常其实你可以分为两类,即一种是常规性的错误,程序也许最多是抛出一个警告,但还是可以继续运行,而另外一种就是无法再运行,基于这两类错误,你可以利用PHP两个不同且很有针对性的两个函数来解决,一个是set_err_handle 还有一个就是register_shutdown_function,这两个函数具体的作用,如果有不懂的去了解一下,我这里就暂时先不讲,卖个关子,很多把第二个大问题说一下后,再统一说明
第二个问题就是用户性的提示,那这类型的提示跟我们的异常系统有什么关系呢,其实只要你稍微的想一下,我想你就应该想通了,很多时候,我们在程序当中加入了捕获语句,并不是真正的捕获程序性的错误,很多是为了捕获因为用户输入时逻辑性的问题而抛出的错误,并给一个相对应的提示,那既然这样,我想凡是需要用户性的提示,也可以集成到异常的处理中来,这样有一个最大好的处就是,程序员只要在程序中写一个抛出语句,并带上相应的提示代码,这个提示代码具体的提示信息,可以用一个配置文件来保存,这样也就达到集中管理这些提示信息的好处了,即使你以后要修改,也相当的方便,当然这也许多少也破坏了接口的定义,但相比之前的提示方式我觉得还是好了不少。
已经说明了大概的处理方法,我在下面就把我在为我们广告分析系统建立的异常处理系统说一下吧。
基于上面两个问题,我可以把上面分为三类异常
致命性的异常
程序性的异常(这个具体需要监测到哪个级别,自己可以设置)
用户信息提示异常
首先我有一个客户端的类,里面有四个方法,一个是构造函数,一个是用于处理致命性错误的静态方法,还有一个是程序性错误的静态方法,还有一个就是最终用于调用不同异常类型的方法。
那这个类自己怎么去调用呢,程序出错了,这个又如何运行呢,
register_shutdown_function (array ('clientException', 'fatalException'));
set_error_handler(array ('clientException', 'runtimeException'), E_USER_ERROR);
利用这两个函数就可以达到自动处理异常的目的了.
下面我把我的结构给大家完全展示出来吧,在异常系统的目录下,有以下文件
clientException.php
errorCodeMap.php
logger.php
systemException.php
userException.php
第一个文件,是外部调用的,就像我上面讲的两个函数,里面的参数就是自动调用该类里面的方法的,注意,这两个方法必须是静态方法,不然会报错,这个文件,除了这两个方法,还有一个构造函数,以及一个用于统一调用不同异常类型CLASS的函数
第二个文件,是一个字典信息文件,一个代码,代表一条提示信息,这个主要是为了让用户性的提示得到统一性的管理
第三个文件,其实就是一个日志文件,用于记录捕获到的致命性错误,以便跟踪改正
第四个文件,是一个程序性错误处理的异常处理类,这个才是真正的异常处理,包括,把错误信息入表,以及决定以何种信息提示用户,这个文件,处理两类异常,一种是程序性异常还有一种就是致命性异常
第五个文件,是用户性的提示,我们在程序中抛出这个错误后,会同时把错误代码传递过来,所以具体的信息获得,以及提示,都在此异常类中处理
我们知道异常系统主要做的作用就是用于跟踪系统的BUG,并把它修正好,在我们的网站系统当中同样也是相当的重要。
一个网站系统,不可能可以永远的保证它能百分百运行良好,很多时候,也许你在一次不经意间的修改当中便使错误发生,这个错误也许是一个警告性的错误,但因为你把错误屏蔽了,暂时不会影响你的程序运行,但也许也会产生一个致命性的错误,这时即使你把错误给屏蔽了,程序也会戛然而止,用户看到的也是一片大白,更别说做别的操作了。
上面那段我更偏向于程序性的错误,但其实在很多时候,也有其它一些情况,如我们在与用户交互过程中,经常需要有一些提示性的错误,由其是在做一些业务性很强的操作时,我们现在做的广告分析系统,便是这样,操作性的提示超多,那如此多的提示信息,就让它显示于你的逻辑性代码之中,然后如果哪一天你需要进行修改提示时,还得一个一个去查找并修改吗?我想这是谁都不想的,说到了这里,也许也会有很多同学认为,这跟我们的异常处理有什么关系呢,先别急,这些问题就是我下面所需要讲解的。
上面已经提出了两大问题,至于怎么解决这两大问题,我说一下我的处理方法
第一类:程序性的错误,我们可以很明确的知道,PHP的异常系统可能使用捕获的方式来获得,但很多时候,但这样需要加入很多的TRY。。。CATCH语句,对于我这样一个对代码美观性要求比较高的人,我并不喜欢这种方式,而且有一种错误,就算我加入了这类捕获语句,我也捕获不到,这类性的错误,就是Fatal Error,对了,就是致命性的错误,至于为什么捕获不到,我记得网上有一篇文章是专门讲这个的,您可以上网百度或者谷歌一下,我也就不讲了,你只要知道,这类性的错误,使用常规性的办法是捕获不到就行了,那既然捕获不到,那万一真用户在操作过程中程序真遇到了这个问题,那怎么办,用户岂不是既看不到结果也看不到提示了,不错,这时如果你没有一个良好 的异常捕获系统,在这点上的用户体验就会差很多,呵,有些同学可能真急了,觉得讲了这么多废话还是没有讲到具体怎么解决,就快了,我们现在已经知道,程序性的异常其实你可以分为两类,即一种是常规性的错误,程序也许最多是抛出一个警告,但还是可以继续运行,而另外一种就是无法再运行,基于这两类错误,你可以利用PHP两个不同且很有针对性的两个函数来解决,一个是set_err_handle 还有一个就是register_shutdown_function,这两个函数具体的作用,如果有不懂的去了解一下,我这里就暂时先不讲,卖个关子,很多把第二个大问题说一下后,再统一说明
第二个问题就是用户性的提示,那这类型的提示跟我们的异常系统有什么关系呢,其实只要你稍微的想一下,我想你就应该想通了,很多时候,我们在程序当中加入了捕获语句,并不是真正的捕获程序性的错误,很多是为了捕获因为用户输入时逻辑性的问题而抛出的错误,并给一个相对应的提示,那既然这样,我想凡是需要用户性的提示,也可以集成到异常的处理中来,这样有一个最大好的处就是,程序员只要在程序中写一个抛出语句,并带上相应的提示代码,这个提示代码具体的提示信息,可以用一个配置文件来保存,这样也就达到集中管理这些提示信息的好处了,即使你以后要修改,也相当的方便,当然这也许多少也破坏了接口的定义,但相比之前的提示方式我觉得还是好了不少。
已经说明了大概的处理方法,我在下面就把我在为我们广告分析系统建立的异常处理系统说一下吧。
基于上面两个问题,我可以把上面分为三类异常
致命性的异常
程序性的异常(这个具体需要监测到哪个级别,自己可以设置)
用户信息提示异常
首先我有一个客户端的类,里面有四个方法,一个是构造函数,一个是用于处理致命性错误的静态方法,还有一个是程序性错误的静态方法,还有一个就是最终用于调用不同异常类型的方法。
那这个类自己怎么去调用呢,程序出错了,这个又如何运行呢,
register_shutdown_function (array ('clientException', 'fatalException'));
set_error_handler(array ('clientException', 'runtimeException'), E_USER_ERROR);
利用这两个函数就可以达到自动处理异常的目的了.
下面我把我的结构给大家完全展示出来吧,在异常系统的目录下,有以下文件
clientException.php
errorCodeMap.php
logger.php
systemException.php
userException.php
第一个文件,是外部调用的,就像我上面讲的两个函数,里面的参数就是自动调用该类里面的方法的,注意,这两个方法必须是静态方法,不然会报错,这个文件,除了这两个方法,还有一个构造函数,以及一个用于统一调用不同异常类型CLASS的函数
第二个文件,是一个字典信息文件,一个代码,代表一条提示信息,这个主要是为了让用户性的提示得到统一性的管理
第三个文件,其实就是一个日志文件,用于记录捕获到的致命性错误,以便跟踪改正
第四个文件,是一个程序性错误处理的异常处理类,这个才是真正的异常处理,包括,把错误信息入表,以及决定以何种信息提示用户,这个文件,处理两类异常,一种是程序性异常还有一种就是致命性异常
第五个文件,是用户性的提示,我们在程序中抛出这个错误后,会同时把错误代码传递过来,所以具体的信息获得,以及提示,都在此异常类中处理
以上就是我整个异常处理的方法.可能还有很多方面没有讲明白,本来想上一个UML图的,但因为时间的原因就没有画了,还有就是里面的日志记录文件,其实可以与日志系统挂钩,这个有时间再讨论,我希望各位同学可以说出自己的建议,或者经验.下面我把clientException.php文件的代码贴出来吧
class clientException { /** * * 异常对象(表示为用户异常还是系统异常,默认为用户异常) **/ private static $exceptionType = 'userException'; /** * * 错误代码,与异常对象的类型相关联(即异常对象为用户异常,该值则表示的是用户异常的错误代码,反之亦然) **/ private static $errorCode = 'unknow'; public function __construct($errorCode = null) { if(!empty($errorCode)) self::$errorCode = $errorCode; self::callException(); } public static function fatalException() { $error = error_get_last(); if(in_array($error['type'], array(1, 64, 2)))//此处是错误类型判断 { self::$exceptionType = 'systemException'; self::$errorCode = 'Fatal_Error'; $param = self::setErrParam($error['type'], $error['message'], $error['file'], $error['line'], 'fatal'); self::callException($param); } } public static function runtimeException($errno, $errstr, $errfile, $errline) { self::$exceptionType = 'systemException'; self::$errorCode = 'User_Error'; $param = self::setErrParam($errno, $errstr, $errfile, $errline, 'warning'); self::callException($param); } public function setErrParam($errno, $errstr, $errfile, $errline, $errtype) { $result['errno'] = $errno; $result['errstr'] = $errstr; $result['errfile'] = $errfile; $result['errline'] = $errline; $result['errtype'] = $errtype; return $result; } public function callException($param = array()) { throw new self::$exceptionType(self::$errorCode, $param); } }