当前位置: 首页 > 后端技术 > PHP

thinkphp源码分析(四)——错误与异常处理篇

时间:2023-03-30 01:38:35 PHP

源码分析错误与异常处理机制错误与异常处理机制文件为/thinkphp/library/think/Error.php,框架指南中的基础文件文件。在php中注册(不知道的可以去《源码分析(二)—入口篇》"),通过thinkError::register()注册。/***注册异常处理*@accesspublic*@returnvoid*/publicstaticfunctionregister(){error_reporting(E_ALL);set_error_handler([__CLASS__,'appError']);set_exception_handler([__CLASS__,'appException']);register_shutdown_function([__CLASS__,'appShutdown']);}这个方法做了四件事:设置所有错误的错误级别E_ALL为E_STRICT设置错误处理函数,set_error_handler([__CLASS__,'appError'])设置异常处理函数,set_exception_handler([__CLASS__,'appException']);设置程序异常终止处理函数,register_shutdown_function([__CLASS__,'appShutdown']);PHP错误级别php的错误级别有:E_STRICT、E_ALL、E_USER_WARNING等,具体请参考【php预定义常量】,thinkError::appError()方法注册在错误处理函数thinkphp来处理错误。/***错误处理*@accesspublic*@paraminteger$errno错误号*@paraminteger$errstr详细错误信息*@paramstring$errfile错误文件*@paraminteger$errline错误行号*@returnvoid*@抛出ErrorException*/publicstaticfunctionappError($errno,$errstr,$errfile='',$errline=0){$exception=newErrorException($errno,$errstr,$errfile,$errline);//匹配异常处理,错误信息管理为think\exception\ErrorExceptionif(error_reporting()&$errno){throw$exception;}self::getExceptionHandler()->report($exception);}在appError方法中,put如果满足异常处理,则将错误信息委托给系统的ErrorException,其他异常通过thinkexceptionHandle处理。//think\exception\ErrorException文件/***ThinkPHP错误异常*主要用于封装set_error_handler和register_shutdown_function获取的错误*除了继承自think\Exception的函数*其他函数与PHP系统\ErrorException基本相同*/classErrorExceptionextendsException{/***用于保存错误级别*@varinteger*/protected$severity;/***错误异常构造函数*@paraminteger$severity错误级别*@paramstring$message错误详情*@paramstring$file错误文件路径*@paraminteger$line错误行号*@paramarray$context错误上下文,它将包含错误触发器范围内所有变量的数组*/publicfunction__construct($severity,$message,$file,$line,array$context=[]){$this->severity=$severity;$this->message=$message;$this->file=$file;$this->line=$line;$this->代码=0;空($上下文)||$this->setData('错误上下文',$context);}/***获取错误级别*@return整数错误级别*/finalpublicfunctiongetSeverity(){返回$this->严重性;}}errorException设置错误级别、错误信息、错误文件路径、行号、上下文异常是thinkexceptionHandle的report()方法:self::getExceptionHandler()->report($exception);//self::getExceptionHandler()/***获取异常处理实例*@accesspublic*@returnHandle*/publicstaticfunctiongetExceptionHandler(){static$handle;if(!$handle){//异常处理句柄$class=Config::get('exception_handle');如果($class&&is_string($class)&&class_exists($class)&&is_subclass_of($class,"\\think\\exception\\Handle")){$handle=new$class;}else{$handle=newHandle;如果($classinstanceof\Closure){$handle->setRender($class);}}}返回$句柄;这里有一个关键点:static$handle;直到脚本结束才会被销毁。这个逻辑是判断$handle是否已经赋值,如果没有赋值,则获取默认配置文件是否设置了handle句柄。如果设置,句柄必须是\think\exception\Handle的子类(is_subclass_of($class,"\think\exception\Handle")),如果不设置,则使用默认的thinkexceptionHandle调用report方法进行处理,并将其记录在日志文件中。/***报告或记录异常。**@param\Exception$exception*@returnvoid*/publicfunctionreport(Exception$exception){if(!$this->isIgnoreReport($exception)){//收集异常数据if(App::$debug){$data=['file'=>$exception->getFile(),'line'=>$exception->getLine(),'message'=>$this->getMessage($exception),'code'=>$this->getCode($exception),];$log="[{$data['code']}]{$data['message']}[{$data['file']}:{$data['line']}]";}else{$data=['code'=>$this->getCode($exception),'message'=>$this->getMessage($exception),];$log="[{$data['code']}]{$data['message']}";}如果(配置::得到('record_trace')){$log.="\r\n".$exception->getTraceAsString();}日志::记录($log,'error');}}将errorException的数据组装成对应的字符串,写日志异常处理函数thinkphp注册thinkError::appException()方法来处理错误。/***异常处理*@accesspublic*@param\Exception|\Throwable$eexception*@returnvoid*/publicstaticfunctionappException($e){if(!$einstanceof\Exception){$e=newThrowableError($e);}$handler=self::getExceptionHandler();$处理程序->报告($e);如果(IS_CLI){$handler->renderForConsole(newConsoleOutput,$e);}else{$handler->render($e)->send();方法和appError处理类似,基本都是获取ExceptionHandle然后调用handle的report方法,但是多了一个步骤来呈现异常,如果是写到命令行输出,如果是web,返回错误信息通过response响应给客户端。在thinkphp异常终止时执行的函数中注册了thinkError::appShutdown()方法来处理错误。/***异常终止处理*@accesspublic*@returnvoid*/publicstaticfunctionappShutdown(){//管理错误信息到think\ErrorExceptionif(!is_null($error=error_get_last())&&self::isFatal($error['type'])){self::appException(newErrorException($error['type'],$error['message'],$error['file'],$error['line']));}//写入日志Log::save();}获取error_get_last()抛出的最后一个错误,将信息委托给thinkErrorException,通过异常处理函数记录信息。最后写入日志。总结一下,整体的错误处理机制是获取ExceptionHandle,然后调用句柄的report方法,只是多了一个步骤来呈现异常。如果是在命令行写到命令行输出,如果是web的话,错误信息会通过response响应返回给客户端。.默认句柄是thinkexceptionHandle。当然你也可以自定义handle,但是必须是thinkexceptionHandle的子类。通过self::getExceptionHandler的is_subclass_of($class,"\think\exception\Handle")可以知道。