Laravel 6 资源类不支持构造函数自动依赖注入,因其非容器解析实例,而是通过 new static() 或 Resource::make() 直接创建;正确方式包括:方式一在 toArray() 中用 app() 按需获取服务,方式二手动传入服务实例,方式三绑定资源工厂。

在 Laravel 6 中,资源类(Resource)默认**不支持自动依赖注入**,因为它们不是由服务容器解析和实例化的——而是通过 new static() 或 Resource::make() 等静态方式直接创建的。所以不能像控制器或中间件那样,在构造函数里写类型提示就自动注入服务。
为什么资源类不能直接用构造函数注入?
资源类的设计定位是「数据转换层」,职责单一:把模型或数组转成 API JSON 结构。Laravel 不会对每个资源实例走容器解析流程,因此:
- 构造函数参数不会被容器自动解析
- 类型提示(如
MyService $service)会被忽略或报错 - 手动 new 资源时,必须自己传入所有参数,无法享受 DI 的便利
在资源类中安全使用依赖注入的三种方式
方式一:通过静态方法或辅助方法传入依赖(推荐)
不在构造函数里依赖,而是在转化逻辑中按需获取服务:
- 用
app()在toArray()或with()中临时解析服务(适合轻量、无状态操作) - 示例:
$cache = app(CacheManager::class); return $cache->get('key'); - 注意:避免在大量资源循环中频繁调用
app(),可考虑提前注入到实例属性(见方式二)
方式二:在资源实例化时手动传入服务(可控且清晰)
显式构造资源并传入所需服务实例:
- 定义带参数的构造函数:
public function __construct(private MyService $service) {} - 调用时:
UserResource::make($user)->withService(app(MyService::class)) - 或统一包装:
new UserResource($user, app(MyService::class)) - 优点:依赖明确、可测试、不绕过容器
方式三:使用容器绑定自定义资源工厂(进阶)
若项目中大量资源需共享同一服务,可注册一个工厂闭包:
- 在
AppServiceProvider@register()中:$this->app->bind(UserResource::class, function ($app) { return new UserResource($app->make(MyService::class)); }); - 之后用
app(UserResource::class)->make($user)获取实例 - 注意:需自行处理模型传参逻辑,不适用于标准
Resource::collection()流程
不建议的做法
以下做法会破坏可维护性或引发运行时问题:
- 在资源中直接
new Service—— 硬编码依赖,无法 mock 测试 - 在
__construct()写类型提示但不手动传参 —— Laravel 6 会报ReflectionException缺少参数 - 滥用
resolve()或全局app()在每个toArray()中 —— 性能隐患且隐藏依赖
本质上,资源类应保持轻量和无副作用。真正需要复杂服务逻辑的,建议提前在控制器或服务层完成处理,再把结果传给资源——这才是 Laravel 6 的设计本意。


















