大家都是怎么设计项目中的传参的?

以前项目中传参基本上如果只有一个参数则直接传,如果多个的话就合并成数组

    public function user(int $id)
    public function users(array $params)

数组的问题是可读性太差了,接收的方法内部可能还需要做一些判断, 后面进行优化,使用了laravel-data 扩展,将验证参数转换成Data对象

<?php

namespace App\Data\User;

use Spatie\LaravelData\Data;

class UserUpdateData extends Data
{
    public function __construct(
        public ?string $nickname,
        public ?string $birthday,
        public ?int $city_id,
        public ?int $height,
        public ?int $weight,
        public ?int $profession_id,
        public ?int $gender
    ) {
    }
}
 public function update(int $userId, UserUpdateData $data)

传对象肯定是比传array的可维护性更好,但是这里有几个纠结的点
根据接口参数定义Data类,同一个controller定义一个Data还是每个接口都定义一个Data呢?
controller 将Data传递到service层,Service层经过处理再传递到Model层,传递的参数可能会发生变化,比如增加其他的字段,service到model层重新创建Data? 这样感觉创建的文件有点多,还会有一定的冗余。
实际项目的传参怎么设计欢迎各位大佬指教交流~

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 30

这就好比Request,有的人就喜欢封装,写多了基本一个接口定义一套,我是觉得很麻烦 :joy:我们之前传params的情况会在注释里把params的字段都列出来,方便后面人维护调用。现在的情况是代码没人review自己定义,我是参数少的,多参数接收传递,加个默认值然后empty判断,参数多的写params,用的时候判断下,必备不存在的还是优先返回,能跑就行

2周前 评论
Pon (楼主) 2周前
陈先生

为此我设计了一个灵活的 DTO ,完全借鉴了 Laravel 的 Attribute

2周前 评论
MrHao 2周前
Pon (楼主) 2周前
MrHao 2周前
33qis 2周前

我用 Request/JsonRequest, 在开头获取所有会用到的数据

2周前 评论
Pon (楼主) 2周前
kis龍 (作者) 2周前

感觉想太多了,一般情况下Request文件里面就已经包含了所有参数

2周前 评论

那么多参数,那么可能要做优化了。

2周前 评论

现在升级到 PHP 8 之后,完全可以使用命名参数

2周前 评论
Pon (楼主) 2周前
Pon (楼主) 2周前

一般接口控制器层面,每个 action 都会有对应的 Request 类吧,如果是这种开发方式,可以将 Request 类和 DTO通过反射结合起来就好了,字段名称只需要定义一次,Service 里面使用 DTO

DTO

class UserDTO extends AbstractDTO{
        #[Validate(rules:['required'])]
        public ?string $nickname,
        public ?string $birthday,
        public ?int $city_id,
        public ?int $height,
        public ?int $weight,
        public ?int $profession_id,
        public ?int $gender
}

Request
通过上面的 DTO 反射生成 Request 类

class UserRequest extends AbstractRequest{
      protected string $dto = UserDTO::class

       public function rules():array{
        // 通过反射生成
      }

      public function getDto():AbstractDTO{
            return new {$this->dto}($this->validated());
      }
}

Controller


class UserController {

   public function user(UserRequest $request){
        $this->userService->user($request->getDto());
   }
}

Service

class UserService {
     public function user(UserDto $dto){
            // ....
     }
}
2周前 评论
Pon (楼主) 2周前
Pon (楼主) 2周前
minororange (作者) 2周前
minororange (作者) 2周前
Pon (楼主) 2周前
Pon (楼主) 2周前
minororange (作者) 2周前
minororange (作者) 2周前
Imuyu 2周前
sanders

听大家推荐过但目前还没用这个包。PHP 的关联数组无法进行元组类型约束那样的效果,肯定还是传对象进行约束更好,也便于一些框架进行编排或进行静态分析。

我的习惯是不太关注文件的多少,当发现重复代码,可以通过 Trait 或 继承 抽象化来实现 DRY (Dont Repeat Yourself)。

2周前 评论

可以只在在 service 层面 做 入参控制

// service
function action(Data $data){ 
// ...
}

在 controller 层 用 request 来控制 入参

// controller

function update(Request $request){

    // 直接采用请求的数据
   $data =  Data::form($request);

   // 自行设置
   $params = $request->all();
   $params['user_id'] = $request->user()->id;
   $data = Data:form($params);
   // 或者使用 additional 追加额外数据
   $data->additional([]);

   $this->service->action($data);

}

controller 只负责对请求参数的一些简单组装操作,业务的参数在 DTO 或者 service 内校验

2周前 评论

要求语义化,扩展性好,可读性高,这必须OOP,每个方法定义个独立的参数类,自己封装下好了。

你可以参考laravel表单验证,每个action定义个独立的request类,定义好参数属性。

2周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!