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

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

    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 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 30

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

11个月前 评论
Pon (楼主) 11个月前

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

11个月前 评论
博学多才的走停 11个月前
Pon (楼主) 11个月前
博学多才的走停 11个月前
33qis 11个月前

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

11个月前 评论
Pon (楼主) 11个月前
kis龍 (作者) 11个月前

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

11个月前 评论

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

11个月前 评论

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

11个月前 评论
Pon (楼主) 11个月前
Pon (楼主) 11个月前

一般接口控制器层面,每个 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){
            // ....
     }
}
11个月前 评论
Pon (楼主) 11个月前
Pon (楼主) 11个月前
minororange (作者) 11个月前
minororange (作者) 11个月前
Pon (楼主) 11个月前
Pon (楼主) 11个月前
minororange (作者) 11个月前
minororange (作者) 11个月前
Imuyu 11个月前
sanders

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

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

11个月前 评论

可以只在在 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 内校验

11个月前 评论

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

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

11个月前 评论