thinkphp 的 service 层必须与容器、psr-4 和生命周期强耦合:需在 composer.json 显式注册 appservice 命名空间并执行 dump-autoload;依赖须通过构造函数类型提示注入,禁用 app()->make();方法名用动词开头,专注事务协调与服务编排,不处理视图、过滤等职责;并发场景下应使用 scoped 绑定或工厂模式隔离上下文。

ThinkPHP 的 Service 层不是“普通 Service 层”的简单平移
它必须和容器、PSR-4、生命周期绑定三者强耦合,否则就退化成普通类——没自动注入、无单例管理、事务拦截器失效、测试难写。所谓“Service 层”,在 ThinkPHP 里本质是 thinkContainer 管理下的业务编排单元,不是目录建了、类写了就叫 Service。
PSR-4 命名空间注册是硬门槛,不执行 composer dump-autoload 就等于没配
ThinkPHP 6/8 默认不扫描 app/service 目录。直接 use appserviceUserService 必报 Class not found。
- 必须在
composer.json的"autoload" → "psr-4"中显式添加:"app\service\": "app/service/" - 改完立刻运行
composer dump-autoload(注意:不是install或update) - 别塞进
app/common或app/library:前者语义不清,后者会被当成工具类加载,和真正通用的Helper混淆
依赖必须走构造函数类型提示,禁止在方法里 app()->make()
临时 make 看似省事,实则绕过容器控制:
- 单例失效:多个地方
make同一个 Service,拿到的是不同实例 - 事务拦截器挂不上:比如
@Transactional注解或中间件依赖容器代理,手动make的对象不受管 - 构造函数应写成:
public function __construct(private OrderService $orderService, private Cache $cache) - 若依赖含请求上下文(如
Request),默认单例会引发并发状态污染——这时得用容器绑定策略(bind+singleton/scoped)或工厂模式
方法命名和事务边界有强约定,不能照搬 Spring 风格
ThinkPHP 的 Service 方法不是“万能胶水”,它只做三件事:协调模型、封装事务、调用外部服务。
- 方法名必须是动词开头:
createOrder()、lockStockAndDeduct(),禁用getOrderInfo()(那是模型的事) - 事务控制必须收口到 Service 方法内部,但仅限该方法自身逻辑闭环;跨 Service 调用(如
OrderService调PaymentService)时,事务应由上层(Controller 或 Command)统一开启 - 禁止在 Service 里做字段过滤、格式转换、
$this->redirect()或渲染视图——这些属于 Controller 或 Logic 层职责 - 参数建议用数组或 DTO 封装,避免堆满
$userId, $productId, $addressId...,后期加字段极易崩
最容易被忽略的是生命周期与上下文的冲突:Service 默认单例,但一旦构造函数注入了带 session 或 request state 的对象(比如绑了 Request 的 Cache 实例),就会在并发请求间共享状态。这时候光注册命名空间、写对构造函数还不够,得配合容器的 scoped 绑定或工厂回调来隔离实例。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











