错误的类型:
1.语法错误:syntax error
2.逻辑错误:比较难以排查因为不是会给一个标准的错误提示
错误报告类型:
- Notice:通知,比如直接使用未定义的变量,不影响PHP正常流程,建议处理这类错误可以使我们的代码更加的严谨。
- Warning:警告,发生了非致命的错误,脚本不会终止运行,但是往往会出现的不是我们想要的结果(如打开文件不存在)。
- Parse error:语法错误,阻止整个脚本执行(没有加分号就是这个错误),所以如果关闭了脚本错误报告这个网页就会打不开返回错误码500。
- Fatal error:这是错误报告里面最严重的而一种错误,这个错误会阻止整个脚本执行(比如说函数同名的情况)。
错误报告的打开与关闭
有两种方式进行控制:
- php.ini 的display_errors =On 或者Off
- 代码里面加上(一般放在第一行,这样下面发生的错误都会1显示/0不显示):
1 |
ini_set('display_errors',1);//或者0 |
注意,如果是fatal error或者parse error都会直接阻止PHP脚本的执行,那么这行显示/或者不显示的指令也不会执行了,这个时候就会按照php.ini里面的设置来执行,因此直接在代码里面加的方式只能是针对Notice和Warning这两种错误类型。因此网站上线应该使用的是php.ini来关闭错误的显示。
错误报告的级别
之前我们是直接打开或者关闭,那么我们能不能只管一些呢?我们就可以使用错误报告级别来关闭/开启
错误级别的设置有两种方式
第一种方式:在通过php.ini的error_reporting = E_ALL进行设置(比如说这里的E_ALL就是对应上图的错误和警告提示)。
EXAMPLE:提示除Notice外的全部错误
1 |
error_reporting = E_ALL ^ E_NOTICE; |
第二种方式:在文件开头
1 |
error_reporting(E_ALL^E_NOTICE); |
关闭PHP所有的错误报告
1 |
error_reporting(0); |
报告所有的错误类型:
1 |
error_reporting(-1); |
1+4+2=7进行上图中前三者的错误级别都显示出来,也可以使用|写错误级别的常量
1 |
error_reporting(7); |
错误处理的最佳实践
- 开发环境下打开错误报告,并且错误报告级别E_ALL
- 正式环境一定要关闭错误报告
- 线上一般会把错误输出到错误报告里面去,而不是直接显示在网页上。
线上错误报告的输出
在php.ini里面有两个参数
- log_errors:是否把脚本的错误报告记录到日志里面On/Off
- error_log:错误报告的日志文件路径
实现自己的错误处理机制
线上环境有一个需求,比如说如果线上的环境出现了一个warning需要发送一封邮件告知开发者去修复这个bug,这个需求php也为我们考虑到了。
用户级别的错误级别常量有三个notice、warning还有一个记不得了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?php function globalErrorHandler($errno,$errstr,$errfile,$errline){ // printf("%d,%s,%s,%s",$errno,$errstr,$errfile,$errline); // if($errno == E_WARNING){ // //发送邮件代码 // echo "mail"; // } switch ($errno) { case E_USER_WARNING: echo 'mail'; break; } // return false;//加上return false会执行标准的php错误处理机制 } // 用globalErrorHandle函数来结果错误处理机制 set_error_handler('globalErrorHandler'); // echo $a; // $fd = fopen('a.txt', 'r'); // 产生一个用户级别的error|notice的错误信息 //业务逻辑 $result = 666; if($result == 666){ trigger_error('666',E_USER_WARNING); } |
异常的抛出和捕获
平时在开发中需要用if去判断很多的错误比如说打开一个文件并写入需要判断
- 格式是否正确
- 是否文件中有内容
- 是否可写
- 是否写入成功了等等…
这样会大大的降低代码的可读性,因此我们需要使用错误处理机制来提高我们书写的代码的可读性。
异常时PHP5提供的特性,是一种面向对象的思想,有四个关键字,只要我们掌握了这四个关键字的用法就可以很好的处理异常了。抛出异常实际上就是抛出一个异常类的对象。
- Try
- throw
- catch
- finally
最基本的异常捕获的结构(伪代码)
1 2 3 4 5 6 7 |
<?php try{ //业务逻辑 if(打开文件不成功) throw new Exception('文件打开失败'); }catch(Exception $e){ //异常处理 } |
try的代码块可以手动的抛出异常
catch接受捕获try中抛出的异常对象,注意try和catch必须组合在一起使用
Exception是php内置的一个异常类,我们要抛出异常实际上是抛出异常的对象。
需要进行异常处理的代码应该放在try代码块内部,以便于抛出异常,catch代码块中包含了对异常的处理。
EXAMPLE:
1 2 3 4 5 6 7 8 9 10 11 |
<?php try{ // 业务逻辑 $result = 1>2; // 如果$result的结果是false就抛出异常 if(!$result){ throw new Exception('exception message'); } }catch(Exception $e){ echo 'exception....'; } |
浏览器输出exception….抛出异常之后程序还会继续执行下去。
我们可以使用finaly来优化代码逻辑,finally一定是放在最后的并且不管有没有异常被捕获finally代码块是一定会执行的!
EXAMPLE:打开文件,无论有没有打开成功我们都是需要关闭文件句柄的,就可以吧关闭文件句柄的功能放在finally里面来执行,这样无论打开与否都会关闭。
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php try{ // 打开文件 echo 'open file'.'<br>'; echo "读文件".'<br>'; throw new Exception('file dose not exist'); }catch(Exception $e){ echo 'exception'.'<br>'; }finally{ // 关闭打开的文件句柄 echo "关闭文件句柄".'<br>'; } |
EXAMPLE:我们也可以把异常对象一层一层的往外抛
1 2 3 4 5 6 7 8 9 10 |
<?php try{ try{ throw new Exception("异常发生了"); }catch(Exception $e){ throw $e; } }catch(Exception $e){ echo "exception..."; } |
注意:PHP5只有少部分的类是支持异常的,大部分的函数和类都只是简单的抛出错误,PHP7之后大部分函数和类都支持抛出异常了。比如PDO已经支持抛出异常了,比如链接数据库的异常:
1 2 3 4 5 6 |
<?php try{ $dbh = new PDO('sadsad','safasd','asdas'); }catch(Exception $e){ echo $e->getMessage(); } |
浏览器输出:不可用数据源
Exception类
也可以通过集成Exception类来实现自定义异常类
捕获多个异常
使用多个catch可以捕获多个异常对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php class FileException extends Exception{} // 文件不存在的异常 class FileNotExistException extends FileException{} // 文件权限异常 class FilePermissionException extends FileException{} function fileHandle(){ // 文件不存在 throw new FileNotExistException('file does not exist'); // 文件权限异常 throw new FilePermissionException('access denied'); // 其他异常 throw new FileException('other exception'); } try{ fileHandle(); }catch(FileNotExistException $e){ echo $e->getMessage(); }catch(FilePermissionException $e){ echo $e->getMessage(); }catch(FileException $e){ echo $e->getMessage(); } |
使用getcode来获取异常:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?php class FileException extends Exception{ //文件不存在 const FILE_NOT_EXIST = 1; //权限不够 const FILE_PERMISSION = 2; } function fileHandle(){ //文件不存在 throw new FileException('FilenotExist',FileException::FILE_NOT_EXIST); //权限不够 throw new FileException('FilePermission',FileException::FILE_PERMISSION); } try { fileHandle(); } catch (Exception $e) { switch ($e -> getCode()) { case FileException::FILE_NOT_EXIST: echo($e->getMessage()); break; case FileException::FILE_PERMISSION: echo ($e -> getMessage()); break; } }catch(Exception $e){ echo 'exception'; } ?> |
使用全局异常处理来捕获漏网之鱼的异常:
1 2 3 4 5 6 7 8 |
<?php function defaultExceptionHandle($e){ printf("uncaught exception:%s in file %s on line %d",$e->getMessage(),$e->getFile(),$e->getLine()); } set_exception_handler('defaultExceptionHandle'); throw new Exception('tese......'); ?> |