异常与错误处理

2023-05-16

异常与错误处理

PHP的异常与错误是分开的,当程序出现异常时会throw一个\Exception(或子类)对象,但是当出现错误时会触发一个错误。

1. 异常处理

1.1 通过try...catch主动处理异常

<?php
/**
 * Class UserNotExistsException
 * @datetime 2020/7/2 5:11 下午
 * @author   roach
 * @email    jhq0113@163.com
 */
class UserNotExistsException extends \Exception
{
}

/**
 * Class TransferException
 * @datetime 2020/7/2 5:13 下午
 * @author   roach
 * @email    jhq0113@163.com
 */
class TransferException extends \Exception
{

}

/**
 * @param int   $inUserId
 * @param int   $outUserId
 * @param float $amout
 * @return bool
 * @throws TransferException
 * @throws UserNotExistsException
 * @datetime 2020/7/2 5:15 下午
 * @author   roach
 * @email    jhq0113@163.com
 */
function transfer($inUserId, $outUserId, $amout)
{
    if($inUserId < 1) {
        throw new UserNotExistsException('入金用户不存在');
    }

    if($outUserId < 1) {
        throw new UserNotExistsException('出金用户不存在');
    }

    if(bccomp($amout, '0', 2) <= 0) {
        throw new TransferException('转账金额必须大于0');
    }

    if(bccomp($amout, '100000000', 2) > 0) {
        throw new \Exception('服务器内部错误');
    }

    return true;
}


try {
    $result = transfer(1,0, 5);
    if($result) {
        exit(json_encode([
            'code' => 200,
            'msg'  => 'success',
            'data' => []
        ]));
    }
}catch (\UserNotExistsException $exception) {
    exit(json_encode([
        'code' => 404,
        'msg'  => $exception->getMessage(),
        'data' => []
    ]));
} catch (\TransferException $exception) {
    exit(json_encode([
        'code' => 501,
        'msg'  => $exception->getMessage(),
        'data' => []
    ]));
} catch (\Exception $exception) {
    throw $exception;
}

以上例程输出:

{"code":404,"msg":"\u51fa\u91d1\u7528\u6237\u4e0d\u5b58\u5728","data":[]}

当开发人员对异常有明确的预期时,可以使用以上的方式,catch不用类型的异常,然后对不用的异常做各种不同的处理。

1.2 set_exception_handler处理异常

PHP可以通过set_exception_handler方法注册一个回调函数,当没有用try...catch捕获的异常都会交个回调函数处理。

同样调用以上转账逻辑,不同的是,把try...catch代码块注释掉,换成如下代码:

set_exception_handler(function ($exception){
    echo $exception->getMessage().PHP_EOL;
});

transfer(1, 1, 0);

以上例程输出:

转账金额不能小于0

从以上例程我们可以看出,set_exception_handler方式适合做默认统一的异常处理,同时也可以加一些统一的处理(如:异常日志、监控报警等)
try...catch适合做一些开发主动捕获异常,通过主动捕获异常做一些特殊需求处理。

2. 错误处理

PHP语言的error分为如下等级:

常量说明备注
E_ERROR1致命的运行时错误。这类错误一般是不可恢复的情况,例如内存分配导致的问题。后果是导致脚本终止不再继续运行
E_WARNING2运行时警告 (非致命错误)。仅给出提示信息,但是脚本不会终止运行
E_PARSE4编译时语法解析错误。解析错误仅仅由分析器产生。
E_NOTICE8运行时通知。表示脚本遇到可能会表现为错误的情况,但是在可以正常运行的脚本里面也可能会有类似的通知。
E_CORE_ERROR16在PHP初始化启动过程中发生的致命错误。该错误类似E_ERROR,但是是由PHP引擎核心产生的。
E_CORE_WARNING32PHP初始化启动过程中发生的警告(非致命错误) 。类似E_WARNING,但是是由PHP引擎核心产生的。
E_COMPILE_ERROR64编译时致命错误。类似E_ERROR, 但是是由Zend脚本引擎产生的。
E_COMPILE_WARNING128编译时警告(非致命错误)。类似E_WARNING,但是是由Zend脚本引擎产生的。
E_USER_ERROR256用户产生的致命错误信息。类似E_ERROR, 但是是由用户自己在代码中使用PHP函数trigger_error()来产生的。
E_USER_WARNING512用户产生的警告(非致命)信息。类似E_WARNING, 但是是由用户自己在代码中使用PHP函数trigger_error()来产生的。
E_USER_NOTICE1024用户产生的通知信息。类似E_NOTICE, 但是是由用户自己在代码中使用PHP函数trigger_error()来产生的。
E_STRICT2048启用PHP对代码的修改建议,以确保代码具有最佳的互操作性和向前兼容性。
E_RECOVERABLE_ERROR4096可被捕捉的致命错误。 它表示发生了一个可能非常危险的错误,但是还没有导致PHP引擎处于不稳定的状态。 如果该错误没有被set_error_handler()捕捉,将成为一个E_ERROR从而脚本会终止运行
E_DEPRECATED8192运行时通知。启用后将会对在未来版本中可能无法正常工作的代码给出警告。
E_USER_DEPRECATED16384用户产生的警告信息。 类似E_DEPRECATED, 但是是由用户自己在代码中使用PHP函数trigger_error()来产生的。
E_ALL30719E_STRICT之外的所有错误和警告信息。

上面的值(数值或者符号)用于建立一个二进制位掩码,来制定要报告的错误信息。可以使用按位运算符来组合这些值或者屏蔽某些类型的错误。请注意,在 php.ini 之中,只有’|’, ‘~’, ‘!’, ‘^’ 和 ‘&’ 会正确解析。

Error层次结构

Throwable
    Error
        ArithmeticError
            DivisionByZeroError
            
        AssertionError
        
        CompileError
            ParseError
            
        TypeError
            ArgumentCountError

2.1 try...catch处理错误

PHP7改变了大多数错误的报告方式。不同于传统(PHP5)的错误报告机制,现在大多数错误被作为Error异常抛出。

try...catch捕捉错误代码格式

<?php
try {
   //你的代码逻辑
} catch (\Throwable $t) {
   //只会在PHP7版本执行,PHP5不会执行
}
catch (\Exception $e)
{
   //只会在PHP5执行,PHP7不会执行
}

案例:

<?php
/**
 * @param int   $inUserId
 * @param int   $outUserId
 * @param float $amout
 * @return bool
 * @datetime 2020/7/2 5:15 下午
 * @author   roach
 * @email    jhq0113@163.com
 */
function transfer($inUserId, $outUserId, $amout)
{
    if($inUserId < 1) {
        trigger_error('入金用户不存在', E_USER_WARNING);
    }

    if($outUserId < 1) {
        trigger_error('出金用户不存在', E_USER_WARNING);
    }

    if(bccomp($amout, '0', 2) <= 0) {
        trigger_error('转账金额必须大于0', E_USER_WARNING);
    }

    if(bccomp($amout, '100000000', 2) > 0) {
        trigger_error('服务器内部错误', E_USER_ERROR);
    }

    return true;
}

try {
    transfer(1, 0, 0);
    fff();
}catch (\Throwable $throwable) {
    echo $throwable->getMessage().PHP_EOL;
}

以上例程输出:

PHP Warning:  出金用户不存在 in Exception.php on line 18
PHP Warning:  转账金额必须大于0 in Exception.php on line 22
Call to undefined function fff()

从以上例程可以看出,并不是所有的error都能被try...catch捕捉到,当调用不存在的方法fff()时,被try...catch捕捉到了。

2.2 set_error_handler捕捉错误

同样调用以上转账逻辑,增加set_error_handler捕获错误,如下:

<?php
/**
 * 致命错误
 */
$fatalError = [
    E_ERROR => 1,
    E_PARSE => 1,
    E_CORE_ERROR => 1,
    E_CORE_WARNING => 1,
    E_COMPILE_ERROR => 1,
    E_COMPILE_WARNING => 1
];

set_error_handler(function() use(&$fatalError){
    $args = func_get_args();
    $throwable = new \ErrorException($args[1], $args[0], 1, $args[2], $args[3]);

    echo $throwable->getMessage().PHP_EOL;
    if(isset($fatalError[ $throwable->getCode() ])) {
        exit();
    }
});

try {
    transfer(1, 0, 0);
    fff();
}catch (\Throwable $throwable) {
    echo $throwable->getMessage().PHP_EOL;
}

以上例程输出:

出金用户不存在
转账金额必须大于0
Call to undefined function fff()

关于异常和错误处理就介绍这么多,大家自动动手封装一个面向对象的通用异常处理吧。

学习更多内容: https://404.360tryst.com

我的视频课程: https://edu.csdn.net/course/detail/9933

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

异常与错误处理 的相关文章

  • oracle 删除表以及回复数据

    找回删除的表 select object name original name partition name type ts name createtime droptime from recyclebin WHERE original n
  • 银行卡信息查询

    银行卡bin 银行卡信息 请移步到github xff1a https github com burningmyself bank
  • ProcessDefinition是干这个用的

    流程定义ProcessDefinition是对业务过程的完整描述 xff0c 例如请假流程定义 报销流程定义等 流程定义的管理包括部署流程定义 查询流程定义 查看流程定义图和删除流程定义 1 部署流程定义 使用RepositoryServi
  • 截取字符串的三种方法

    众所周知 xff0c java提供了很多字符串截取的方式 下面就来看看大致有几种 span class hljs number 1 span span class hljs built in split span 43 正则表达式来进行截取
  • Iterator主要有三个方法:hasNext()、next()、remove()详解

    一 Iterator的API 关于Iterator主要有三个方法 xff1a hasNext next remove hasNext 没有指针下移操作 xff0c 只是判断是否存在下一个元素 next xff1a 指针下移 xff0c 返回
  • @ModelAttribute用法详解

    转载于 xff1a https blog csdn net harry zh wang article details 57329613 之前项目中并自己并没有怎么使用到过 64 ModelAttribute这个注解 xff0c 接手一个老
  • mysql除法运算保留小数的用法

    参照 xff1a https www cnblogs com owenma p 7097602 html 在工作中会遇到计算小数而且需要显现出小数末尾的0 xff0c 我们会用到DECIMAL这个函数 xff0c 这是一个函数非常强悍 xf
  • IDEA—点击文件代码与目录自动同步对应

    关注微信公众号 xff1a CodingTechWork xff0c 一起学习进步 引言 在使用IDEA的时候 xff0c 我们Ctrl 43 Shift 43 F搜索文件后 xff0c 总是要慢慢找文件在哪个包路径下 如查看路径顶端 xf
  • springboot打包完成之后无法读取到resources下的资源文件

    File privateKeyFile 61 ResourceUtils getFile classpath wx pfx PrivateKey privateKey 61 getPrivateKey privateKeyFile priv
  • 接口签名实现拦截的两种方式

    1 采用spring的aop思想进行拦截 需要自定义注解 xff0c 然后定义切面 xff08 五大类 xff09 然后在定义 xff0c 可以获取所有的参数 2 拦截器的实现方式 自定义拦截器 xff0c 然后对拦截器进行配置即可 配置
  • Java程序员利器,lombok神搭档:delombok插件

    Lombok是一款非常实用Java工具 xff0c 它可以帮助开发人员减少样板代码 xff0c 使开发人员专注业务逻辑 xff0c 在Java界几乎无人不知 但也有一些明显的缺点 xff0c 例如 xff1a 对插件强依赖 xff0c 在团
  • C++bind函数

    1 基本概念 bind函数定义在头文件 functional 中 可以将 bind 函数看作一个通用的函数适配器 xff0c 它接受一个可调用对象 xff0c 生成一个新的可调用对象来 适应 原对象的参数列表 C 43 43 Primer
  • C++值的分类 —— 摘自维基百科

    在C 43 43 11 xff0c 对于值的分类 xff0c 要考虑标识 xff08 identity xff09 与可移动性 xff08 movability xff09 xff0c 二者的组合产生了五种分类 xff1a 基础值类型 左值
  • pytorch 深度学习入门代码 (一)线性回归代码实现

    34 34 34 一维线性回归代码实现 34 34 34 import torch from torch autograd import Variable import matplotlib pyplot as plt import tor
  • pytorch 深度学习入门代码 (三)Logistic 回归代码实现

    span class hljs string 34 34 34 Logistic 回归的代码实现 34 34 34 span span class hljs keyword import span matplotlib pyplot spa
  • pytorch 深度学习入门代码 (四)多层全连接神经网络实现 MNIST 手写数字分类

    net py span class hljs keyword import span torch nn span class hljs keyword as span nn span class hljs class span class
  • CentOs云服务器部署项目全流程

    目录 序工具准备putty安装及使用pscp安装及使用 环境安装及配置serverjre 或jdk 安装及配置mysql安装及配置Tomcat 安装及配置 项目部署上传war包至服务器tomcat无法启动常见问题去除端口号和目录名访问项目项
  • 快速上手MybatisPlus

    首先附上mybatis plus官方文档 本篇参考官方文档记录spring mvc项目接入mybatis plus的全流程及一些问题的解决方案 xff0c 建议优先参考官方文档 开始之前 xff0c 假设数据库已建好并已能正常访问 依赖配置
  • FTP工具类一

    public class FTPClientUtils public static String FTPCONFIG 61 34 config ftpConfig properties 34 private static String LO
  • 在 SourceTree 中使用 git rebase (变基)

    原始状态 假如我们要在 master 分支上进行开发 xff0c 在远端的 master 分支上右键 xff0c 检出 一个自己的开发分支 dev 1 做一些开发 xff0c 提交到本地 xff0c 不要推送 xff08 push xff0

随机推荐

  • 云服务器搭建部署全流程

    本篇记录在centos7 3上部署web项目的全流程及一些问题的解决方案 工具准备 putty安装及使用 PuTTY可用来在windows上连接linux服务器 xff0c 可去PuTTY官网下载安装如果不想每次登录都输入密码 xff0c
  • 三种获取字节码对象的方式及区别

    方式一 xff1a 对象 getClass 方法是 根对象Object的方法 是其他类继承Object的getClass方法 方式二 xff1a 类名 class xff0c 你可以理解为字节码本身就是静态的 xff0c 类加载的时字节码就
  • 关于接口与Object 类的关系

    看到这个标题 xff0c 你或许就会想好自己的那份答案 但事实上这个确实没有答案 xff0c 至少没官方证明它们之间的基友关系 看法一 xff1a 因为老师说 xff0c 你可以把接口看作是特殊的类 xff0c 所以不假思索的就认为接口也
  • 单词博弈Java实现(借鉴“miss若尘”博客中写的解题思路)

    单词博弈Java实现 xff0c 已经通过庞果网的用例测试 代码如下 import java util HashMap public class WordGameFinalTest public static int who String
  • mysql安装时的粗心错误:last error unable to update security settings. access denied for user 'root' @ 'localh

    来自 梦想家haima 39 s blog gt http blog dreamwe cn 这个报错出现在mysql最后 当你看到mysql的最后一步需要设置密码可能你开心得很 Mysql就快安装好了 赶快输入三行密码都是root 结果报下
  • @SuppressWarnings

    简介 xff1a java lang SuppressWarnings是J2SE 5 0中标准的Annotation之一 可以标注在类 字段 方法 参数 构造方法 xff0c 以及局部变量上 作用 xff1a 告诉编译器忽略指定的警告 xf
  • 欢迎使用CSDN-markdown编辑器

    欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来 xff0c 用它写博客 xff0c 将会带来全新的体验哦 xff1a Markdown和扩展Markdown简洁的语法代码块高亮图片链接和图片上传
  • Linux之强大的awk

    来自 梦想家 Haima s blog gt http blog dreamwe cn awk简介 awk是Linux中的一个命令 xff0c 用来做文本处理与分析 xff0c 功能简单强悍 xff0c 同时它也是一门编程语言 awk处理文
  • 手机抓包charles使用

    使用的是charles window 之前使过fiddler但是感觉并没有charles好用以及一目了然 链接 https pan baidu com s 1NMNXa8M4niLObQKIsCNL3A 提取码 2wsa 安装包可以通过连接
  • 安卓Tinker热更新接入踩坑(minSdkVersion 21)

    哎哟 xff0c 这个坑啊 我项目采用的是ARouter 43 Tinker 我接入的是tinkerpathchttp www tinkerpatch com Docs intro按照文档对接 xff0c 我采用的是reflectAppli
  • Android 解压和重新打包system.img

    开始我们的工作前 xff0c 请记住 xff0c Linux一定要学会用file命令分析文件类型 xff0c 这样才好入手 xff0c 否则错了都不知道怎么回事 xff01 xff01 xff01 1 解压system img 先用file
  • Jetpack系列学习笔记整理一 之LifeCycles

    学习最好的途径就是官网和github Demo xff0c 先放链接 xff0c 想看自行跳转 xff1a 官网 xff1a https developer android com topic libraries architecture
  • 获取安卓位置信息

    别忘了添加权限 xff1a lt uses permission android name 61 34 android permission INTERNET 34 gt lt uses permission android name 61
  • 安卓与html混合开发之原生与js相互调用

    原生和html的优缺点就不多说了 xff0c 有些特定条件下用html页面可以很方便 xff0c 也很容易更新和维护 xff0c 那么这就涉及到html与安卓原生的交互和通信 接下来我要分享的是html调用原生的弹窗和位置信息 xff0c
  • 应用保活--杀死进程也能收到推送消息

    我选取的是极光推送 xff0c 当把进程杀死时候就接受不到推送过来的消息 这是因为我使用的是小米手机 xff0c 小米和华为手机属于那种深度定制安卓系统 xff0c 需要用户的操作才能够实现应用 保活 的目的 小米 MIUI 自启动管理 x
  • 安卓原生与vue前段相互调用

    之前写过一个博客是安卓原生与JS交互的博客 xff1a http blog csdn net jhl122 article details 53406623 那是正常情况下的交互 xff0c 但是如果前段人员使用vue开发就会产生一个问题
  • CMake 编译时报错 ninja: error: ......missing and no known rule to make it

    Build command failed Error while executing process F Android sdk cmake 3 6 4111459 bin cmake exe with arguments build E
  • 数据类型和Json格式

    1 前几天 xff0c 我才知道有一种简化的数据交换格式 xff0c 叫做yaml 我翻了一遍它的文档 xff0c 看懂的地方不多 xff0c 但是有一句话令我茅塞顿开 它说 xff0c 从结构上看 xff0c 所有的数据最终都可以分成三种
  • golang语言rsa加解密及签名验签

    golang语言rsa加解密及签名验签 96 rsa 96 算法概述 96 Rsa 96 结构体封装封装的优点使用案例 rsa算法 概述 rsa是一种非对称的可逆的加密算法 xff0c 对加密数据长度有限制 xff0c 同时rsa也提供了数
  • 异常与错误处理

    异常与错误处理 PHP的异常与错误是分开的 xff0c 当程序出现异常时会throw一个 Exception 或子类 对象 xff0c 但是当出现错误时会触发一个错误 1 异常处理 1 1 通过try catch主动处理异常 span cl