在PHP的学习过程中,我们会接触到两个概念,一个是错误,一个是异常。啥玩意?他们不是一个东西嘛?如果接触过Java、C#之类的纯面向对象语言的同学,可能对异常是没有什么问题,毕竟所有的问题都可以try...catch来解决。但是像PHP这种从面向过程发展到面向对象的语言来说,错误和异常就是两个完全不同的东西了。

我们将用一系列的文章来彻底的搞懂PHP中的错误和异常到底是怎么回事,有哪些处理这些错误和异常的机制,我们应该如何对待它们。

什么是错误?

错误,一般是由PHP本身的因素所导致的问题,错误的语法、环境的配置不当等都会引起错误。错误和php.ini文件当中的error_reporting参数有直接的关系。相信大家都配过这个参数。一般会把它配置为 E_ALL & ~E_NOTICE 。这是什么意思呢?我们先来看看PHP中有哪些错误类型:

  • Fatal Error:致命错误(脚本终止运行)

    • E_ERROR // 致命的运行错误,错误无法恢复,暂停执行脚本
    • E_CORE_ERROR // PHP启动时初始化过程中的致命错误
    • E_COMPILE_ERROR // 编译时致命性错,就像由Zend脚本引擎生成了一个E_ERROR
    • E_USER_ERROR // 自定义错误消息。像用PHP函数trigger_error(错误类型设置为:E_USER_ERROR)
  • Parse Error:编译时解析错误,语法错误(脚本终止运行)

    • E_PARSE //编译时的语法解析错误
  • Warning Error:警告错误(仅给出提示信息,脚本不终止运行)

    • E_WARNING // 运行时警告 (非致命错误)。
    • E_CORE_WARNING // PHP初始化启动过程中发生的警告 (非致命错误) 。
    • E_COMPILE_WARNING // 编译警告
    • E_USER_WARNING // 用户产生的警告信息
  • Notice Error:通知错误(仅给出通知信息,脚本不终止运行)

    • E_NOTICE // 运行时通知。表示脚本遇到可能会表现为错误的情况.
    • E_USER_NOTICE // 用户产生的通知信息。

在配置文件中的 E_ALL & ~E_NOTICE 就是显示所有错误但通知错误类错误除外的意思。当然,我们在代码中也可以手动的改变这种错误信息的通知。

error_reporting(E_ALL);

通过这行代码,我们就让当前文件代码中的错误全部显示出来了。Notice 和 Warning 类型的错误是不会中断代码运行的,他们是通知和报警,并不是致命的错误。而其他类型的错误则会中断代码的执行。

$a = 100 / 0; // Warning: Division by zero
echo $f; // Notice: Undefined variable: f
test(); // Fatal error: Uncaught Error: Call to undefined function test() echo 1;

上述代码中分别是Warning的除0错误警告和echo $f;的未定义变量提示,这两行代码都是可以在报错后可以继续向下运行的。而未定义的方法则是Fatal级别的致命错误了。所以最后那个1也不会输出了。

那么错误要如何处理呢?原则上我们应该是要去消灭这些错误的,因为他们基本上不会是我们写代码的逻辑没理清而产生的逻辑错误,是实打实的一些语法及环境错误,这种错误在生产环境是不应该出现的。同时,它们与异常最最重要的一个区别就是,它们无法通过try...catch进行捕获。也就是说,这种错误没有非常好的错误后处理机制。

try {
$a = 100 / 0; // Warning: Division by zero
echo $f; // Notice: Undefined variable: f
} catch (Excepiton $e) {
print_r($e); // 无法捕获
}

不过,PHP还是提供了一些处理错误的函数供我们使用。

  1. set_error_handler()

基本上只能处理 Warning 和 Notice 级别的错误。

set_error_handler(function( $errno , $errstr ){
echo 'set_error_handler:', $errno, $errstr, PHP_EOL;
});
$a = 100 / 0; // Warning: Division by zero
echo $f; // Notice: Undefined variable: f
test(); // Fatal error: Uncaught Error: Call to undefined function test() // set_error_handler:2Division by zero
// set_error_handler:8Undefined variable: f

从代码中可以看出,Fatal error这种致命错误并没有捕获到。

  1. register_shutdown_function()

其实它也不是用来处理错误的,这个函数的作用是在发生致命错误,程序停止前最后会调用的一个函数。可以用来记录日志或者关闭一些重要的外部句柄,不过在生产环境中,我们一般会用php.ini中的log_error来进行日志的记录。所以这个函数也用得并不多。

register_shutdown_function(function(){
echo 'register_shutdown_function:', PHP_EOL;
print_r(error_get_last());
});
test(); // register_shutdown_function:
// Array
// (
// [type] => 1
// [message] => Uncaught Error: Call to undefined function test() in /php/202002/source/一起搞懂PHP的错误和异常(一).php:16
// Stack trace:
// #0 {main}
// thrown
// [file] => /php/202002/source/一起搞懂PHP的错误和异常(一).php
// [line] => 16
// )

这个函数的回调函数中没有任何的参数变量,所以我们需要通过 error_get_last() 来拿到本次执行中发生的所有错误情况。另外要注意的是,只有在运行时产生的错误都会调用到这个注册函数的回调中,编译时的错误是也是无法通过这个函数捕获到的,比如直接的语法错误:

register_shutdown_function(function(){
echo 'register_shutdown_function:', PHP_EOL;
print_r(error_get_last());
}); test(a+-); // Parse error: syntax error, unexpected ')'

总结

综上所述,就像在文章前面说过的,错误是应该尽量不要带到生产环境中去的,它们并没有很好的处理机制。或者说,错误就是我们要尽量避免的东西,因为大部分情况下它和我们的逻辑代码并没有太大的关系。而且严重的错误会直接导致程序运行的中止,无法像异常一样通过catch机制保证程序继续运行。

下一篇我们将继续学习下一个知识点:异常及其处理机制。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202002/source/%E4%B8%80%E8%B5%B7%E6%90%9E%E6%87%82PHP%E7%9A%84%E9%94%99%E8%AF%AF%E5%92%8C%E5%BC%82%E5%B8%B8%EF%BC%88%E4%B8%80%EF%BC%89.php

参考文档:

https://www.cnblogs.com/zyf-zhaoyafei/p/6928149.html

https://www.php.net/manual/zh/language.errors.basics.php

https://www.php.net/manual/zh/errorfunc.constants.php

https://www.php.net/manual/zh/errorfunc.configuration.php#ini.error-reporting

https://www.php.net/manual/zh/function.error-reporting.php

https://www.php.net/manual/zh/function.set-error-handler.php

https://www.php.net/manual/zh/function.register-shutdown-function.php

一起搞懂PHP的错误和异常(一)的更多相关文章

  1. 一起搞懂PHP的错误和异常(三)

    关于错误与异常的最后一篇文章,我们来进行一些总结. PHP中错误和异常的区别 通过前面两篇文章的学习,我们来直接将错误和异常摆上来进行对比,看看他们的区别与联系: 错误的出现通常是语法或编译运行时错误 ...

  2. 一起搞懂PHP的错误和异常(二)

    上回文章中我们讲到了错误是编译和语法运行时会出现的,它们与逻辑无关,是程序员在码代码时不应该出现的,也就是说,这些错误应该是尽量避免带到线上环境的,他们不能通过try...catch捕获到.而异常则正 ...

  3. 不想再被鄙视?那就看进来! 一文搞懂Python2字符编码

    程序员都自视清高,觉得自己是创造者,经常鄙视不太懂技术的产品或者QA.可悲的是,程序员之间也相互鄙视,程序员的鄙视链流传甚广,作为一个Python程序员,自然最关心的是下面这幅图啦 我们项目组一值使用 ...

  4. 一文搞懂所有Java集合面试题

    Java集合 刚刚经历过秋招,看了大量的面经,顺便将常见的Java集合常考知识点总结了一下,并根据被问到的频率大致做了一个标注.一颗星表示知识点需要了解,被问到的频率不高,面试时起码能说个差不多.两颗 ...

  5. Java进阶专题(二十六) 将近2万字的Dubbo原理解析,彻底搞懂dubbo

    前言 ​ 前面我们研究了RPC的原理,市面上有很多基于RPC思想实现的框架,比如有Dubbo.今天就从Dubbo的SPI机制.服务注册与发现源码及网络通信过程去深入剖析下Dubbo. Dubbo架构 ...

  6. 一文搞懂如何使用Node.js进行TCP网络通信

    摘要: 网络是通信互联的基础,Node.js提供了net.http.dgram等模块,分别用来实现TCP.HTTP.UDP的通信,本文主要对使用Node.js的TCP通信部份进行实践记录. 本文分享自 ...

  7. 五分钟搞懂POM设计模式

    转载请注明出处️ 作者:IT小学生蔡坨坨 原文链接:五分钟搞懂POM设计模式 大家好,我是IT小学生蔡坨坨. 今天,我们来聊聊Web UI自动化测试中的POM设计模式. 为什么要用POM设计模式 前期 ...

  8. WebAPI 用ExceptionFilterAttribute实现错误(异常)日志的记录(log4net做写库操作)

    WebAPI 用ExceptionFilterAttribute实现错误(异常)日志的记录(log4net做写库操作) 好吧,还是那个社区APP,非管理系统,用户行为日志感觉不是很必要的,但是,错误日 ...

  9. 每个java初学者都应该搞懂的问题

    对于这个系列里的问题,每个学JAVA的人都应该搞懂.当然,如果只是学JAVA玩玩就无所谓了.如果你认为自己已经超越初学者了,却不很懂这些问题,请将你自己重归初学者行列.内容均来自于CSDN的经典老贴. ...

随机推荐

  1. Vue系列-03-vue-cli自动化工具

    使用Vue-CLI创建项目 安装vue-cli脚手架 Mac安装vue-cli脚手架 lichengguo@lichengguodeMacBook-Pro ~ % sudo npm install - ...

  2. 面向对象第一单元总结:Java实现表达式求导

    面向对象第一单元总结:Java实现表达式求导 题目要求 输入一个表达式:包含x,x**2,sin(),cos(),等形式,对x求导并输出结果 例:\(x+x**2+-2*x**2*(sin(x**2+ ...

  3. Shellshock 破壳漏洞 Writeup

    破壳漏洞 CVE编号:CVE-2014-6271 题目URL:http://www.whalwl.site:8029/ 提示:flag在服务器根目录 ShellShock (CVE-2014-6271 ...

  4. pikachu 不安全的url跳转

    不安全的url跳转问题可能发生在一切执行了url地址跳转的地方.如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话就可能发生&q ...

  5. luogu P6239 奇怪的道路

    奇怪的道路 我看不出来是状压的状压 好吧,其实看到k的范围应该去往状压方面想的. 然后,题目中说"任何一个城市都与恰好偶数条道路相连(0也被认为是偶数)". 所以,奇偶,两种状态可 ...

  6. C# prism 框架

    定义Region (RegionManager) 定义Region 的方式有两种,一个是在XMAL界面指定,另一种这是代码当中指定. RegionManager.RegionName(XMAL) Re ...

  7. C# 学习笔记(三)----- 设备监视 ( System.Management )

    实例:串口监视 using System; using System.Collections.Generic; using System.Linq; using System.Text; using ...

  8. [SWMM]弗汝德数

    弗汝德数(Froude number)是流体内惯性力与重力的比值.弗汝德数(Fr)是水力学中重要的无量纲数之一,它表示过水断面上单位重量液体具有的平均动能与平均势能的比值,它也表示水流惯性力与重力的比 ...

  9. linux(3)--------SSH工具的安装使用

    0.一般安装服务端的Linux ssh是默认安装的可以运行ssh localhost测试一下是否可以链接 1.SSH是什么 1)ssh:Secure Shell  安全外壳协议 2)建立在应用层基础上 ...

  10. 写webpack插件报警告Tapable.plugin is deprecated. Use new API on .hooks instead解决方案,webpack4插件新写法

    最近写了个小插件报了个警告,然后去百度了一下,全都给我说extract-text-webpack-plugin这个插件有问题要更新,我也是无语了,这个插件我用都没用,百度翻了下齐刷刷全是这个答案,搞得 ...