• 如何设计PHP业务模块(函数/方法)返回结果的结构?


    如题:如何设计业务模块返回结果的结构?

    一个业务函数/方法执行后,对外输出数据的结构通常有以下几种:

    1、返回数字,如 成功时返回 0,失败时返回 -1,有的还会用一个全局变量输出错误信息:

    <?php
    class UserLogic extends ThinkModel {
    	protected $error;
    
    	/**
    	 * 更改用户名称
    	 *
    	 * @param int    $userId   用户ID
    	 * @param string $userName 用户名
    	 * @return int -1: 操作失败, 0: 操作成功
    	 */
    	public function updateUserName($userId = 0, $userName = '') {
    		if (empty($userId)) {
    			$this->error = '用户ID不能为空';
    			return -1;
    		}
    
    		if (empty($userName)) {
    			$this->error = '用户名不能为空';
    			return -1;
    		}
    
    		$where = array(
    			'userId' => $userId
    		);
    
    		$data = array(
    			'userName' => $userName
    		);
    
    		$res = $this->where($where)->save($data);
    		if ($res !== false) {
    			return 0;
    		}
    
    		return -1;
    	}
    }

    2、返回 bool 值,如成功时返回 true,失败时返回 false。

    例子跟上面的差不多,这里就不写了。

    3、抛出异常

    可以使用类似以下代码抛出异常:

    throw new Exception('用户ID不能为空');

    更详细的 PHP 抛出异常,可以阅读先前的文章:PHP中的错误处理、异常处理机制详解

    不过,我不建议在 业务函数中,使用 throw new Exception('xxx') 方式抛出异常,在一些基础框架中使用它比较合适,比如:

    (1).文件不存在时;

    (2).类不存在时;

    (3).方法/函数名不存在时;

    (4).数据库连接失败时;

    等等情况。

    4、返回一个数组结构,如

    <?php
    class UserLogic extends ThinkModel {
    	/**
    	 * 更改用户名称
    	 *
    	 * @param int    $userId   用户ID
    	 * @param string $userName 用户名
    	 * @return array
    	 */
    	public function updateUserName($userId = 0, $userName = '') {
    		$return = array(
    			'code' => 0,			// 状态码, 0: 操作失败, 1: 操作成功
    			'msg' => '操作失败',		// 消息语
    			'data' => array()		// 如果需要, 可以附带数据
    		);
    
    		if (empty($userId)) {
    			$return['msg'] = '用户ID不能为空';
    			return $return;
    		}
    
    		if (empty($userName)) {
    			$return['msg'] = '用户名不能为空';
    			return $return;
    		}
    
    		$where = array(
    			'userId' => $userId
    		);
    
    		$data = array(
    			'userName' => $userName
    		);
    
    		$res = $this->where($where)->save($data);
    		if ($res !== false) {
    			$return['code'] = 1;
    			$return['msg'] = '操作成功';
    		}
    
    		return $return;
    	}
    }

    5、返回一个类实例:

    上面返回一个统一的数组结构,我还是蛮喜欢的,在项目中,也使用过一段时间,

    但是,越来越发现,在每个函数开头,都要事先写个 $return 数组结构,还是挺麻烦的。

    $return = array(
    	'code' => 0,			// 状态码, 0: 操作失败, 1: 操作成功
    	'msg' => '操作失败',		// 消息语
    	'data' => array()		// 如果需要, 可以附带数据
    );

    我们可以改造下,让它面向对象化。

    首先,定义一个 业务操作结果类:Result.class.php

    <?php
    namespace Think;
    
    /**
     * 业务操作结果类
     *
     * @package Think
     * @autor 52php.cnblogs.com
     */
    Class Result {
    	public $code = '';			// 状态码: success-成功, fail-失败
    	public $msg = '';			// 消息
    	public $data = array();		// 数据
    
    	/**
    	 * 实例化
    	 */
    	public static function instance() {
    		return new self();
    	}
    
    	/**
    	 * 设置 状态码
    	 *
    	 * @param string $code 状态码
    	 * @return $this
    	 */
    	public function code($code = null) {
    		!is_null($code) && ($this->code = $code);
    		return $this;
    	}
    
    	/**
    	 * 设置 消息
    	 *
    	 * @param string $msg 消息
    	 * @return $this
    	 */
    	public function msg($msg = null) {
    		!is_null($msg) && ($this->msg = $msg);
    		return $this;
    	}
    
    	/**
    	 * 设置 数据
    	 *
    	 * @param array $data 数据
    	 * @return $this
    	 */
    	public function data($data = null) {
    		!is_null($data) && ($this->data = $data);
    		return $this;
    	}
    
    	/**
    	 * 成功
    	 *
    	 * @param string $msg 消息
    	 * @param array  $data 数据
    	 * @return $this
    	 */
    	public function success($msg = null, $data = null) {
    		$this->code = 'success';
    		is_null($msg) && ($this->msg === '') && ($this->msg = '操作成功');
    		!is_null($msg) && ($this->msg = $msg);
    		!is_null($data) && ($this->data = $data);
    
    		return $this;
    	}
    
    	/**
    	 * 失败
    	 *
    	 * @param string $msg 消息
    	 * @param array  $data 数据
    	 * @return $this
    	 */
    	public function fail($msg = null, $data = null) {
    		$this->code = 'fail';
    		is_null($msg) && ($this->msg === '') && ($this->msg = '操作失败');
    		!is_null($msg) && ($this->msg = $msg);
    		!is_null($data) && ($this->data = $data);
    
    		return $this;
    	}
    
    	/**
    	 * 是否为 成功
    	 */
    	public function isSuccess() {
    		return ($this->code == 'success') ? true : false;
    	}
    
    	/**
    	 * 是否为 失败
    	 */
    	public function isFail() {
    		return ($this->code != 'success') ? true : false;
    	}
    
    	/**
    	 * 输出 (json数据)
    	 */
    	public function output() {
    		header('Content-type:text/json');
    
    		$res = array(
    			'code' => $this->code,
    			'msg' => $this->msg,
    			'data' => $this->data,
    		);
    
    		if (isset($_REQUEST['jsoncallback'])) {
    			echo $_REQUEST['jsoncallback'] . '(' . json_encode($res) . ')';
    		} else {
    			echo json_encode($res);
    		}
    
    		die();
    	}
    }

    这样,每个业务函数,统一输出 Result 类实例,一个业务函数调用另外一个或多个业务函数时,处理 业务异常 非常方便!

    应用举例:

    (1).业务模型中

    <?php
    namespace CommonModel;
    
    use ThinkModel;
    use ThinkResult;
    
    class UserLogic extends Model {
    	/**
    	 * 更改用户名称
    	 *
    	 * @param int    $userId   用户ID
    	 * @param string $userName 用户名
    	 * @return Result
    	 */
    	public function updateUserName($userId = 0, $userName = '') {
    		if (empty($userId)) {
    			return Result::instance()->msg('用户ID不能为空')->fail();
    		}
    
    		if (empty($userName)) {
    			return Result::instance()->msg('用户名不能为空')->fail();
    		}
    
    		$where = array(
    			'userId' => $userId
    		);
    
    		$data = array(
    			'userName' => $userName
    		);
    
    		$res = $this->where($where)->save($data);
    		if ($res !== false) {
    			return Result::instance()->msg('操作成功')->success();
    		}
    
    		return Result::instance()->msg('操作失败')->fail();
    	}
    }

    (2).控制器中

    <?php
    namespace CommonModel;
    
    use ThinkController;
    
    class UserController extends Controller {
    	/**
    	 * 更改用户名称
    	 */
    	public function updateUserName() {
    		$userId = I('REQUEST.userId');
    		$userName = I('REQUEST.userName');
    
    		// "开启" 事务
    		D('User')->startTrans();
    
    		$result = D('User', 'Logic')->updateUserName($userId, $userName);
    		if ($result->isSuccess()) {
    			// "提交" 事务
    			D('User')->commit();
    		} else {
    			// "回滚" 事务
    			D('User')->rollback();
    		}
    
    		// 输出 API 的 json 结果 (主要是给 移动端 提供接口)
    		$result->output();
    	}
    }

    API返回的结果结构如下:

    {
        "code":"success",
        "msg":"操作成功",
        "data":[]
    }

    如何定义 API 输出结果的结构?

    可以先阅读下文章:App架构设计经验谈:服务端接口的设计

    一般也是定义一个统一的结构,如:

    {
        "code":"0",
        "msg": "success",
        "data": { "key1": "value1", "key2": "value2", ... }
    }

    很多人对这个“统一的输出结构”还是挺喜欢的,但是又发现他们对这个 code 值的设计 或 理解 或 使用 又是不对的。业界也没有统一的规则,所以比较乱象。

    比如说,定义“code=400”,表示 “验证失败”,开发人员只要遇到“验证失败”的情况,统统返回 code=400 的错误状态码,

    如:“用户不存在时”返回 code=400,“开始时间大于结束时间”也返回 code=400,“评论的内容不能为空”也返回 code=400,这样的设计和使用都是不对的。

    如果非要把 code 的值设计为编码(一串数字,或一串数字和字母的组合)的话,它具有两层含义,一方面代表“状态码”,是成功还是失败,另一方面代表“错误码”,哪里出错了,出什么错。

    同时,它还应该具有以下特性:

    (1).唯一性

    即一个编码代表具体的某个异常,如果 用 “code=400” 表示“评论的内容不能为空”的异常,就不能用“code=400”表示 “开始时间大于结束时间”的异常。

    (2).多语言性

    官方只需要对这个code错误码用一种语言(如英文)来描述错误详情,不同的开发使用者可以根据自己平台的需要,把这个错误信息(依据code)翻译成其他语言,如 中文,俄文等等。

    (3).模块性

    比如,用1开头的code值,表示某个模块里抛出的异常,用2开头的code值,表示另外一个模块抛出的异常。

    可以参考下各大平台对 code 值的设计:

    1、微信公众号

    http://mp.weixin.qq.com/wiki/10/6380dc743053a91c544ffd2b7c959166.html

    2、开心网

    http://wiki.open.kaixin001.com/index.php?id=%E9%94%99%E8%AF%AF%E4%BB%A3%E7%A0%81%E9%87%8A%E4%B9%89

    最后的建议:

    如果你的项目不是“开放平台”类型(自己内部使用),再加上项目开发时间又比较紧,一时又没想好如何规划code值的时候,建议 code 只定义为 2 个值,成功时返回为“success”,失败时返回为“fail”。不要使用“true”和“false”,因为它们是各个开发语言的关键字,避免不必要的麻烦。

      


    后记:

    对旧项目的“返回一个数组结构”的业务模块接口,做了个小调整:

    封装了一个函数,方便初始化,如:

    <?php
    /**
     * 创建 业务函数/方法的(统一的)返回结构
     *
     * @param int    $code 状态码 0-操作失败,1-操作成功
     * @param string $msg  消息语
     * @param array  $data 返回数据
     * @return array
     */
    function core_return($code = 0, $msg = '操作失败', $data = array()) {
    	return array(
    		'code' => $code,
    		'msg' => $msg,
    		'data' => $data
    	);
    }

    业务函数中,可这样初始化

    $return = core_return();
    
  • 相关阅读:
    SLAM+语音机器人DIY系列:(二)ROS入门——3.在ubuntu16.04中安装ROS kinetic
    SLAM+语音机器人DIY系列:(二)ROS入门——2.ROS系统整体架构
    2017年 年计划
    125. Valid Palindrome
    一道多树递归面试题
    顺序表查找和有序表查找
    c++中常见概念、关键字等的区别
    两个栈实现一个队列,两个队列实现一个栈
    150. Evaluate Reverse Polish Notation
    堆排序
  • 原文地址:https://www.cnblogs.com/52php/p/5684531.html
Copyright © 2020-2023  润新知