PHP 错误和异常处理(上)
1、错误报告
设置错误级别
在 PHP 5 中,程序错误会被划分为多种级别:https://www.php.net/manual/zh/errorfunc.constants.php,然后可以通过 error_reporting 函数设置报告的错误级别:
error_reporting(E_ALL); // 报告所有 PHP 错误
error_reporting(0); // 关闭所有 PHP 错误报告
error_reporting(-1); // 与上面?操作相反,也是报告所有 PHP 错误
当然,更常见的是通过位运算 报告特定级别的错误:
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
要排除对 E_NOTICE
级别的错误报告可以这么做:
error_reporting(E_ALL ^ E_NOTICE);
如果没有在 PHP 应用程序中调用 error_reporting
设置错误报告级别,则会应用 PHP 全局配置文件 php.ini
中默认的错误报告级别。我们可以在命令行通过 php -i | grep error_reporting
查看本地环境下这个默认配置值:
32767
对应的错误级别是 E_ALL
,这可以在所有错误级别中查询得出。
基本使用
下面举个简单的例子来测试错误报告,我们在 php_learning/oop
目录下新建一个 error.php
来存储测试代码。
在上篇教程中,反序列化一个未在当前文件中定义的类时,会抛出 E_NOTICE
级别的错误,而试图访问一个不存在的 URL 链接或者除数为 0,会抛出 E_WARNING
级别的错误,我们以访问不存在的 URL 为例:
这个时候没有配置错误报告级别,默认报告所有级别的错误,此时如果我们排除对 E_WARNING
级别错误的报告,则执行代码不会报错,同时打印函数返回的结果 false
:
自定义错误处理器
另外,你还可以通过 set_error_handler 函数指定自定义错误处理器对错误进行处理,自定义处理器通常是个自定义函数,在这个函数中,我们可以自定义不同级别错误的处理逻辑:
<?php
// error_reporting(E_ALL); // 报告所有错误(默认配置)
// error_reporting(E_ALL ^ E_WARNING);
set_error_handler("myErrorHandler");
$content = file_get_contents('https://xueyuanjun.com/error');
var_dump($content);
/**
* 自定义错误处理器
* @param $errno int 错误级别
* @param $errstr string 错误信息
* @param $errfile string 错误文件
* @param $errline int 错误行号
*/
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
// 该级别错误不报告的话退出
if (!(error_reporting() & $errno)) {
return;
}
switch ($errno) {
case E_ERROR:
echo "致命错误类型: [$errno] $errstrn";
break;
case E_WARNING:
echo "警告错误类型: [$errno] $errstrn";
break;
case E_NOTICE:
echo "一般错误类型: [$errno] $errstrn";
break;
default:
echo "未知错误类型: [$errno] $errstrn";
break;
}
}
运行上述代码,输出如下:
可以看到,错误报告变成了自定义错误处理器输出的内容,并且,也不会终止程序的继续运行,因为我们并没有在处理器中退出程序。
将错误报告写入日志
我们可以通过 set_error_handler
函数定义一个全局的自定义错误处理机制,另外,错误报告默认输出到标准输出 STDOUT 中了,我们还可以通过 error_log 函数将其输出到指定日志文件:
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
...
$logDir = __DIR__ . DIRECTORY_SEPARATOR . 'logs';
if (!file_exists($logDir)) {
mkdir($logDir);
}
$logFile = $logDir . DIRECTORY_SEPARATOR . 'err.log';
switch ($errno) {
case E_ERROR:
error_log("致命错误: [$errno] $errstr", 3, $logFile);
break;
case E_WARNING:
error_log("警告: [$errno] $errstr", 3, $logFile);
break;
case E_NOTICE:
error_log("通知: [$errno] $errstr", 3, $logFile);
break;
default:
echo "未知错误类型: [$errno] $errstrn";
break;
}
}
在写入指定日志文件之前,先通过 PHP 文件系统函数 创建对应的日志目录(运行 PHP 脚本所在目录下创建 logs
子目录),生成的日志将存放在该目录下,然后在写入日志函数 error_log
中,第一个参数是错误消息,第二个参数是写入目标(3 表示指定文件,1 表示邮箱,0 表示系统日志),第三个参数即目标值,这里是自定义的日志文件。
运行上述代码:
-w647
可以看到 STDOUT 中不再输出日志,而是写入到 oop/logs/err.log
文件中:
2、Error 异常
不同于 PHP 5 的错误报告机制,在 PHP 7 中,大多数错误被作为 Error 异常抛出,这种 Error 异常可以像 Exception 那样被捕获,如果没有对 Error 异常进行捕获,则调用全局异常处理器(通过 set_exception_handler 函数注册)处理,如果全局异常处理器也没有注册,则按照传统错误报告方式处理,就像我们上面演示的那样,如果通过 try/catch
语句捕获,对应捕获代码如下:
<?php
// error_reporting(E_ALL); // 报告所有错误(默认配置)
// error_reporting(E_ALL ^ E_WARNING);
// set_error_handler("myErrorHandler");
try {
$content = file_get_contents('https://xueyuanjun.com/error');
} catch (Error $error) {
var_dump($error);
}
var_dump($content);
上述代码的打印结果如下:
但是需要注意的是,如果设置不报告 WARNING
级别的错误,则不会抛出 Error
异常,另外,如果通过 set_error_handler
设置了自定义错误处理器,则优先应用该配置,也不会抛出 Error 异常。
另外,和传统错误报告一样,你可以通过设置 display_errors
选项决定是否向用户显示错误报告和 Error 异常,该配置默认在 PHP 配置文件中全局设置,你也可以通过 ini_set 在运行时设置:
ini_set('display_errors', 0);
该值默认为 1,表示显示用户级错误,设置为 0 则表示不显示用户级错误,你可以自行测试下设置与否对错误输出的影响。还有一个与之类似的全局配置 display_startup_errors
,表示是否显示 PHP 启动过程中的错误信息,设置逻辑也是一样。建议在线上环境将这两个配置值都设置为 0。
和其他 PHP 异常类型不同,Error
异常和 Exception
类并不是父子关系,而是兄弟关系,所以不能通过 Exception 捕获 Error 异常,关于异常捕获和处理机制的更多细节,我们将在下一篇教程中详细探讨。
(全文完)
- Centos 下非 Root 安装 Microsoft R Open
- 下载TCGA所有癌症的maf文件做signature分析
- 比对NR库看看物种分布【直播】我的基因组88
- 探究某个基因的外显子覆盖度情况【直播】我的基因组87
- PHP底层的运行机制与原理
- CHROME开发者工具的小技巧
- 48条高效率的PHP优化写法
- 生信蓝领,一个不舍得分享的高通量数据分析框架
- 为什么in_array(0, ['a', 'b', 'c'])返回true
- Java 10 新特性解密,引入类型推断机制,将于 2018 年 3 月 20 日发布
- 肿瘤全外显子测序数据分析流程大放送
- 数据预处理 | 机器学习之特征工程
- 书写高质量jQuery代码的6条经验
- Thread ThreadLocal,傻傻分不清
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- SAS-新规试行下诞生的程序
- AIOHTTP的实战(一)
- JMeter二次开发插件实例
- 「R」Obtain RNAseq Values for a Specific Gene in Xena Database
- 使用JMeter测试TCP协议
- SQL使用(一):如何使用SQL语句去查询第二高的值
- OpenCV加载图片显示对应类型(位深度)方法
- 小程序快速入门教程(登录注册、开发工具、文件及结构介绍)
- 面试题-统计字符出现最大次数
- pytorch中文语言模型bert预训练代码
- React环境搭建
- leetcode - 旋转数组的最小数字
- 笔记101 | 文件的压缩与解压笔记
- 诸葛亮vs司马懿,排序算法大战谁能笑到最后?
- Centos密钥登陆,解决云服务器被尝试登陆问题