PHP/TP5 接口设计中异常处理

PHP提供 Exception 类来处理异常

new Exception(‘错误信息(默认为空)‘,‘错误代码(默认0)‘,‘异常链中前一个异常‘)

然后可以通过

e -> getMessage() 获取异常信息
e -> getCode() 获取异常错误码

处理异常

        try {
            //可能抛出异常代码
            throw new Exception("Error Processing Request", 1);
        } catch (Exception $e) {
            // 1. 记录日志
            // 2. 处理异常,程序继续进行 / 继续向上抛出异常 / 终止程序,打印异常错误
        }

在ThinkPHP中,框架自带异常处理类,返回错误信息以HTML页面形式展示,如果程序出现错误开发人员没有主动捕捉异常,则会被框架捕捉,然后抛出HTML

当在接口设计中时,由于无法得知客户端类型,所以HTML的形式客户端可能无法解析,此时便需要重写异常类,以json的形式返回错误信息给客户端

异常分类:

  • 自定义异常:通常是由客户端传递参数错误导致,此类异常不需要记录日志,但需要返回错误原因
  • 服务器异常:代码错误导致异常,此类异常需要记录日志,但不需要返回错误原因

服务器异常错误一般由PHP或者框架抛出,自定义异常需要手动捕捉,然后抛出

实现:

在Application/common目录下新建 exception 目录,此目录为异常类库目录

Application/common/exception/ExceptionHandler (重写后的异常处理类)

<?php
namespace app\common\exception;

use Exception;
use think\exception\Handle;
use think\facade\Request;
use think\Log;

class ExceptionHandler extends Handle {

    private $code;
    private $msg;
    private $errorCode;

    public function render(Exception $e) {
        if ($e instanceof BaseException) {
            //如果是自定义异常,则控制http状态码,不需要记录日志
            //因为这些通常是因为客户端传递参数错误或者是用户请求造成的异常
            //不应当记录日志

            $this->code = $e->code;
            $this->msg = $e->msg;
            $this->errorCode = $e->errorCode;
        } else {
            // 如果是服务器未处理的异常,将http状态码设置为500,并记录日志
            if (config(‘app_debug‘)) {
                // 调试状态下需要显示TP默认的异常页面,因为TP的默认页面
                // 很容易看出问题
                return parent::render($e);
            }

            $this->code = 500;
            $this->msg = ‘sorry,we make a mistake. (^o^)Y‘;
            $this->errorCode = 999;
            $this->recordErrorLog($e);
        }

        $request = Request::instance();
        $result = [
            ‘msg‘ => $this->msg,
            ‘error_code‘ => $this->errorCode,
            ‘request_url‘ => $request = $request->url(),
        ];
        return json($result, $this->code);
    }

    /*
             * 将异常写入日志
    */
    private function recordErrorLog(Exception $e) {
        Log::init([
            ‘type‘ => ‘File‘,
            ‘path‘ => LOG_PATH,
            ‘level‘ => [‘error‘],
        ]);
        Log::record($e->getMessage(), ‘error‘);
    }

}

这个类会判断异常来源,并作出相应处理

创建处理类后,需要修改对应配置文件,让这个类成为框架默认异常处理类

在application/config/app.php

    // 异常处理handle类 留空使用 \think\exception\Handle
    ‘exception_handle‘ => ‘\app\common\exception\ExceptionHandler‘,

Application/common/exception/BaseException (自定义异常类基类,基础PHP自带异常类Exception)

<?php
namespace app\common\exception;
use think\Exception;

/**
 * Class BaseException
 * 自定义异常类的基类
 */
class BaseException extends Exception {
    public $code = 400;
    public $msg = ‘invalid parameters‘;
    public $errorCode = 999;

    /**
     * 构造函数,接收一个关联数组
     * @param array $params 关联数组只应包含code、msg和errorCode,且不应该是空值
     */
    public function __construct($params = []) {
        if (!is_array($params)) {
            return;
        }
        if (array_key_exists(‘code‘, $params)) {
            $this->code = $params[‘code‘];
        }
        if (array_key_exists(‘msg‘, $params)) {
            $this->msg = $params[‘msg‘];
        }
        if (array_key_exists(‘errorCode‘, $params)) {
            $this->errorCode = $params[‘errorCode‘];
        }
    }
}

自定义异常类

Application/common/exception/UserException (自定义异常,这里举例User模块的异常)

<?php

namespace app\common\exception;

class UserException extends BaseException {
    public $code = 404;
    public $msg = ‘用户不存在‘;
    public $errorCode = 60000;
}

抛出自定义异常

    try {
            //todo...
            throw new \app\common\exception\UserException();

        } catch (Exception $e) {

        }

此时异常展示不再是TP自带的HTML页,而是

{
    "msg": "用户不存在",
    "error_code": 60000,
    "request_url": "/wx_shop/public/index.php/admin/banner/list"
}

  

原文地址:https://www.cnblogs.com/xiaoliwang/p/9345088.html

时间: 2024-08-28 13:22:21

PHP/TP5 接口设计中异常处理的相关文章

python接口设计中的__all__和del

最近在实现python接口中遇到了一些小问题,解决后总结如下. 目的:在设计接口时,只暴露某个文件的特定方法. 例如: t.py import os import sys def a(): pass def b(): pass def c(): pass 假设我们要开发的插件名为Shona,如果我们在设计插件时,在__init__.py文件中进行如下操作: from t import * 如上import后,调用时可见方法: Shona.t.a() Shona.t.b() Shona.t.c()

[接口设计]从客户端的角度设计后端的接口

前言 兵马未动,粮草先行.在一款APP产品的各个版本迭代中,兵马的启动指的是真正开始敲代码的时候,粮草先行则是指前期的需求,交互,UI等评审准备阶段,还有本文要说的接口的设计与评审.虽然很多时候一个api接口的业务,数据逻辑是后端提供的,但真正使用这个接口的是客户端,一个前端功能的实现流程与逻辑,有时候只有客户端的RD才清楚,从某种意义来说,客户端算是接口的需求方.所以建议在前期接口设计和评审时,客户端的RD应该更多的思考和参与,什么时机调什么接口?每个接口需要哪些字段?数据含义怎么给?只有这些

接口设计·

在大公司里工作,业务都已经拆分掉,必然用服务化中间件来将各个业务的服务串联起来,那很显然,你会调用别人的接口,或者你的系统本身也要提供一些接口出去,我只是根据我的感受简单说一下,接口设计中的注意事项 一般情况下,我们都用maven来管理项目,对外接口一般会放到一个独立的模块中,暴露出去:所以第一点要注意的是,这个独立的module尽可能不要依赖任何第三方jar,更不用说那些很重的框架或者别的业务方的jar,因为这种反例我见过太多了,我不想在这里吐槽,因为这实在太糟糕了,我们一直强调弱依赖,低耦合

HTTP接口设计及日志打印

任何一个稍大的项目中,web接口的使用是少不了的,不管C2S还是S2S都会依赖于http的接口.下面对这一两年来写过各种Http接口做一个总结. 大致可以分为以下五点: 1.使用requestId来记录追踪请求 2.只在body中接收json字符串的请求,避免产生编码问题 3.返回适当的数据结构 4.打印有用的日志 5.提供可阅读的文档 第一点,使用requestId来记录追踪请求.如果你这么做了,当你查找定位问题的时候就会知道这是一个多么有用的规则.这里可以强制请求中用UUID作为reques

go语言学习笔记---非入侵式接口设计探究

关键词:非入侵式 首先我们要知道什么是入侵式接口, 比如定义了接口 Person接口:Fight(),Play(),Zhimaoyi(),Zuofan()方法 Women接口:Zhimaoyi(), Zuofan()方法 Man接口:Fight(),Play()方法 classPerson类实现了Person接口的所有方法 在传统的oo编程语言中,为了得到一个Man的对象,至少要写一个classMan类去实现Man接口,为了得到一个Women的对象又不得不写一个classWomen类去实现Wom

在Java API设计中,面向接口编程的思想,以及接口和工厂的关系

现在的java API的设计中,提倡面向接口的编程,即在API的设计中,参数的传递和返回建议使用接口,而不是具体的实现类,如一个方法的输入参数类型应该使用Map接口,而不是HashMap或Hashtable等具体的实现类.这样做的好处是,程序容易扩展.如果使用Map作为参数,用户可以使用任何实现Map接口的类作为参数,而不是仅仅限制使用HashMap或Hashtable作为参数,使程序的实现更加灵活. 接口(Java的Interface),只定义了一些抽象的方法(也可以定义一些常量,但不鼓励这么

C++ 11可变参数接口设计在模板编程中应用的一点点总结

概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量(或属性,C#中属性和成员变量还是有区别的): 类的成员方法: 从编译器的角度看,我们必须明确指定以上3部分,才算完整地定义了一个类并且编译通过. 所谓的“类弱化”,是指类的设计者在定义类的时候,并没有完整定义一个类,而是把类的其中一部分的定义留给类的使用者. 从传统才c++98看,通过模板类,使用

【Android】透明状态栏在App中的实现与接口设计

By Sodino 文章目录 1. 认识透明状态栏 2. 透明状态栏Api及特性 3. 设置透明状态栏 4. 处理消失的系统状态栏区域 5. fitsSystemWindows 6. Activity中的接口设计 7. Fragment中的接口设计 8. 白色Titlebar的处理 9. 小米 与 魅族 与 (莫名其妙的)华为 10. 腾讯优测UTest GitHub源码:TransparentStatusbar源码中分两个app TestBasic: 透明状态栏实现的示例,方便debug 白色

面向对象设计中抽象类与接口的区别

在OOD(面向对象设计)中,经常会用到抽象类或接口,[注:在C++中,没有接口的概念,只有抽象类:而在Java中两者都存在].而在使用过程中,也许会有不少人认为接口和抽象类差不多,然后就想当然地觉得可以相互完全替换.事实上,虽然他们有很多相似点,但也有很大差异. 1.抽象类与接口的出现条件 在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样.并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类.抽象类往往用来表征我们