Service类必须注册PSR-4命名空间并执行composer dump-autoload,依赖须通过构造函数类型提示注入,禁止手动new或app()->make(),方法仅协调模型、封装事务、实现业务规则,命名用动词开头且不得处理请求响应。

不能直接 new UserService(),也不能用 app()->make(UserService::class) 临时获取——这两种写法都会绕过容器生命周期,导致事务失效、单例错乱、依赖未注入,最终在并发或复杂逻辑下出问题。
Service 类必须注册 PSR-4 命名空间并重载自动加载
ThinkPHP 6 默认不识别 app/service/ 目录。硬建文件后 use appserviceUserService 会报 Class not found。
- 在
composer.json的"autoload" → "psr-4"中追加:"app\service\": "app/service/" - 执行
composer dump-autoload(漏掉这步等于没改) - 别把 Service 放进
app/common或app/library:前者语义模糊,后者会被当成通用工具类加载,和真正需容器管理的业务服务混在一起
依赖必须通过构造函数类型提示注入
控制器里不能手动 new,也不能在方法里 app()->make();否则 $this->request 是 null、事务拦截器不触发、AOP 失效——这不是“能跑就行”,是“表面能跑,线上崩得悄无声息”。
- 正确写法:
public function __construct(private UserService $userService) - 框架会在实例化控制器时自动解析并注入,保证单例、事务上下文、中间件状态完整
- 强依赖(如
OrderService需要StockService)也必须提前声明,不能等方法里才去取
Service 方法命名和职责边界要清晰
Service 不是“啥都往里塞”的中转站。它只做三件事:协调多模型操作、封装事务、实现跨域业务规则。其他一律不碰。
立即学习“PHP免费学习笔记(深入)”;
- 方法名用动词开头:
createOrder()、lockAndDeductStock(),别写getUserInfo()(那是模型的事) - 禁止在 Service 里调用
$this->redirect()、view()或做字段过滤/格式转换——这些属于控制器或 Logic 层 - 如果方法依赖
Request或带 session 的缓存实例,说明它不该是单例,得改用工厂绑定或方法内构建,否则并发下状态会串
最常被忽略的是:Service 默认单例,但一旦构造函数里注入了请求相关对象,就可能在高并发下共享状态。这时候光注册命名空间和构造注入还不够,得配合容器绑定策略调整生命周期。



















