php使用Result类优雅的处理业务逻辑返回值

所属分类:php | 发布于 2023-05-02 14:01:55

怎么处理业务逻辑的返回值,一直是困扰自己的一个问题,我们来分析一下。

直到在学习iOS开发过程中,发现在Swift中是使用Result<Data, Error>来处理返回值的,当时就感觉这思想是真的好。后来又在网上看到了,原来在2015的时,就有人出了类似的php版本,真是相见恨晚。

在php中,一般将业务逻辑写在Model中,我们拿一个登录逻辑来举例。

在登录过程中,用户输入用户名和密码,业务逻辑处理登录逻辑,登录过程中,可能发生用户不存在和用户密码错误情况。当登录成功时返回当前的用户信息。

我们来看看处理业务逻辑的三种方法。

第一种方法,登录成功返回用户信息,登录失败返回false

use think\Model;

class User extends Model
{
    public function login($username, $password) {
        if (!$user = User::where('username', $username)->find()) {
            // 用户不存在
            return false;
        }
        if (!password_verify($password, $user['password'])) {
            // 用户密码错误
            return fasle;
        }
        return $user;
    }
}

用这种方法处理业务逻辑,在控制器无法区分出登录失败的具体原因,抛弃掉。

第二种方法,使用编码来区分业务逻辑

use think\Model;

class User extends Model
{
    public function loginWithCode($username, $password) {
        $result['code'] = 0;
        if (!$user = User::where('username', $username)->find()) {
            // 用户不存在
            $result['code'] = 101;
            $result['message'] = '用户不存在';
            return $result;
        }
        if (!password_verify($password, $user['password'])) {
            // 用户密码错误
            $result['code'] = 102;
            $result['message'] = '密码错误';
            return result;
        }
        $result['user'] = $user;
        return $result;
    }
}

使用这种方法,返回值是一个包含code字段的数组,当code=0时表示成功,其它情况则表示失败,当失败时,返回message字段,来标记错误原因。

其实这种处理方法,已经基本满足了各种要求,算是处理返回值的一种比较好的方法。

第三种方法,使用Result类来处理业务逻辑返回值

这种方法其实算是第二种方法的改进版。

1、先引入Result类

/**
 * 返回结果类
 * 可用于各种业务逻辑处理
 */

namespace app\extendLibs;

class Result
{

    const SUCCESS = 'success';
    const FAIL = 'fail';

    protected $resultStatus = ''; // 状态码: success-成功,fail-失败
    protected $resultCode = null; // 业务编码: 根据业务需要而定
    protected $resultMessage = null;   // 业务消息: 根据业务需要而定
    protected $data = [];   // 返回数据

    // 静态实例
    private static $instance = null;

    // 单例获取方法
    public static function getInstance()
    {
        if (self::$instance == null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    // 禁止被实例化
    private function __construct()
    {

    }

    // 禁止clone
    private function __clone()
    {

    }

    /**
     * 设置状态
     * @param $code
     * @return $this
     */
    public function setCode($code = null)
    {
        !is_null($code) && ($this->resultCode = $code);
        return $this;
    }

    /**
     * 获取code
     * @return null
     */
    public function getCode()
    {
        return $this->resultCode;
    }

    /**
     * 设置消息
     * @param $message
     * @return $this
     */
    public function setMessage($message = null)
    {
        !is_null($message) && ($this->resultMessage = $message);
        return $this;
    }

    /**
     * 获取message
     * @return null
     */
    public function getMessage()
    {
        return $this->resultMessage;
    }

    public function data($data = null)
    {
        !is_null($data) && ($this->data = $data);
        return $this;
    }

    /**
     * 获取data
     * @return array
     */
    public function getData()
    {
        return $this->data;
    }

    public function success($data = null)
    {
        $this->resultStatus = self::SUCCESS;
        !is_null($data) && ($this->data = $data);
        return $this;
    }

    public function fail($message = null, $code = null)
    {
        $this->resultStatus = self::FAIL;
        $this->resultCode = $code;
        $this->resultMessage = $message;
        return $this;
    }

    public function isSuccess() {
        return $this->resultStatus == self::SUCCESS;
    }

    public function isFail() {
        return $this->resultStatus == self::FAIL ? true : false;
    }

}

2、Result说明

2.1 Result类提供success()和fai()两个方法,用来在Model层返回业务逻辑。

2.2 Result类提供isSuccess()和isFail()两个方法,用来在Controller层判断业务逻辑结果。

2.3 Result类提供了message和code两个可选变量,可以根据需要选择。

3、Model层使用Result类返回业务逻辑

use think\Model;
use app\extendLibs\Result;

class User extends Model
{
    public function loginWithResult($username, $password) {
        $result = Result::getInstance();
        if (!$user = User::where('username', $username)->find()) {
            // 用户不存在
            return $result->fail("用户不存在", 101);
        }
        if (!password_verify($password, $user['password'])) {
            // 用户密码错误
            return $result->fail('密码错误', 102);
        }
        return $result->success($user);
    }
}

4、Controller层处理业务逻辑结果

class UserController extends BaseController
{
    protected $user;
    protected function initialize()
    {
        parent::initialize();
        $this->user = new User();
    }

    public function login()
    {
        $username = input('post.username');
        $password = input('post.password');
        $result = $this->user->login($username, $password);
        if ($result->isSuccess()) {
            $data = $result->getData();
            // .... 返回结果
            return json();
        } else {
            $code = 100; // 这里可以是系统定义状态码
            // $message = '****'; 这里也可以是系统统一的提示信息
            $message = $result->getMessage();
            $sub_code = $result->getCode(); // 这里是业务状态码,可选择返回与否
            // 返回结果
            return json();
        }
    }
}

示例结束,基本上是达到了想要的效果,终于能优雅的处理业务逻辑的返回值了。

文哥博客(https://wenge365.com)属于文野个人博客,欢迎浏览使用

联系方式:qq:52292959 邮箱:52292959@qq.com

备案号:粤ICP备18108585号 友情链接