model 层只负责数据存取与基础 crud,封装数据库映射及访问器、修改器、关联关系和自动验证;service 层负责业务编排、事务控制与跨系统交互,是业务逻辑唯一出口,二者职责不可越界。

Model 层只管“数据怎么存、怎么取”
Model 的核心职责是映射数据库表,封装基础的 CRUD 和简单数据处理。它不关心业务规则、不处理 HTTP 上下文、也不调用其他模型或外部服务。
常见错误现象:save() 里写事务逻辑、getInfo() 中拼接第三方 API 请求、在 UserModel 里直接调用 OrderModel::create()。
- 允许:定义访问器(
getFullnameAttr)、修改器(setPasswordAttr)、关联关系(hasOne、hasMany) - 允许:设置自动验证(
validate配置)、自动完成(auto字段) - 禁止:调用
Db::transaction()、Http::post()、Cache::get()等非数据层操作 - 禁止:接收
$request或$response对象,Model 不该感知请求生命周期
Service 层负责“这件事该怎么做成”
Service 是业务逻辑的唯一出口。它协调多个 Model、控制事务边界、处理跨系统交互、实现可复用的流程封装。TP8 明确把 app/service/ 作为一级目录,不是可选项,而是分层落地的关键位置。
使用场景举例:用户下单 → 扣库存 + 创建订单 + 发送通知 + 更新积分。这四个动作不能全塞进 OrderModel::create(),而应由 OrderService::placeOrder() 统一编排。
- 必须:用构造函数或方法参数注入依赖的 Model 或其他 Service(如
UserService、InventoryService) - 必须:显式开启事务(
Db::transaction()),并在异常时回滚 - 推荐:方法命名体现业务语义,如
applyRefund()、syncUserToCrm(),而非updateData() - 注意:TP8 容器支持自动解析类型提示,
public function __construct(UserModel $user, OrderService $order)可直接工作
别让 Model 和 Service 职责互相越界
最常踩的坑是“Model 里写一半业务,Service 里再补一半”,结果改个折扣规则要动三个文件。根本判断标准就一条:这段代码如果抽离出当前项目,是否还能独立复用?
容易混淆的边界:
-
UserModel::checkPassword($raw)✅ 合理:密码校验属于数据对象自身能力 -
UserModel::login($credentials)❌ 错误:登录含会话创建、失败计数、验证码校验等,应移至UserLoginService -
OrderService::createOrder($data)✅ 合理:聚合用户、商品、地址、库存等多个 Model 操作 -
OrderService::getOrderList($page)❌ 危险:分页查询本质是数据读取,应交还给OrderModel::with(['user', 'items'])->paginate(),Service 只做参数过滤和权限检查
复杂点在于:有些逻辑看似“数据相关”,实则已滑向业务。比如“获取用户最近三笔未完成订单”,表面是查询,但“未完成”的定义可能随营销活动变化——这种规则必须收口到 Service,Model 只提供原始数据集。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











