本文目录导读:

- 方案一:写在模型(Model)—— 推荐(胖模型,瘦控制器)
- 方案二:写在控制器(Controller)—— 不推荐(瘦模型,胖控制器)
- 方案三:写在服务层(Service Layer)—— 适合大型复杂项目(推荐升级)
- 总结:到底放哪?
- 行业通用准则(经验总结)
在 PHP 开发中,业务逻辑应该放在哪里是一个经典问题,但没有绝对的答案,取决于你的架构模式、项目规模和团队规范。
以下是最主流的三种方案,以及它们的适用场景和优缺点:
写在模型(Model)—— 推荐(胖模型,瘦控制器)
这是 MVC 的经典思想,也是目前 Laravel、Symfony 等主流框架社区大力推崇的做法。
核心原则: 控制器只负责“接收请求”和“返回响应”,所有的业务规则、计算、校验都放在模型类中。
-
代码示例:
// 控制器 class OrderController extends Controller { public function store(Request $request) { // 1. 只做参数接收(或表单请求校验) // 2. 调用模型的方法处理业务 $order = Order::createOrder($request->user(), $request->all()); return response()->json($order); } } // 模型或服务类 class Order extends Model { public static function createOrder(User $user, array $data) { // 业务逻辑:检查库存、计算价格、生成订单号等 if ($data['quantity'] > $product->stock) { throw new \Exception('库存不足'); } // ... 复杂的业务计算 $order = self::create([...]); // 记录日志、发送通知等 return $order; } } -
优点: 控制器非常薄,易于测试;业务逻辑复用性强(API 和 Web 同时调用同一模型方法)。
-
缺点: 模型可能会变得非常庞大(上帝类),如果业务复杂,需要进一步拆分服务层。
写在控制器(Controller)—— 不推荐(瘦模型,胖控制器)
通常出现在初学者代码或快速原型中。
核心原则: 所有逻辑都写在 store()、update() 等方法里。
- 缺点: 控制器充满了
if...else和 SQL 片段,极难测试和维护;业务逻辑无法复用;违反单一职责原则。
写在服务层(Service Layer)—— 适合大型复杂项目(推荐升级)
当业务逻辑非常复杂(涉及多模型交互、外部 API 调用、消息队列)时,把逻辑放在模型里会让模型过于臃肿,此时会引入 Service(服务)层。
核心原则: 模型只负责数据表映射(ORM),控制器调用 服务类,服务类专门承载业务规则。
-
代码示例:
// 1. 服务类 class OrderService { public function checkout(User $user, Cart $cart) { // 聚合操作多个模型 $total = $this->calculatePrice($cart); $order = Order::create([...]); // 这里只写数据操作,不写复杂的业务判断 $this->paymentGateway->charge($user, $total); return $order; } } // 2. 控制器注入服务 class OrderController extends Controller { public function __construct(private OrderService $orderService) {} public function store(Request $request) { $order = $this->orderService->checkout($request->user(), $request->cart); return response()->json($order); } }
到底放哪?
| 场景 | 推荐位置 | 理由 |
|---|---|---|
| CRUD 简单逻辑 (增删改查,薄校验) |
模型(Model) | 直接写在模型静态方法中,简单快捷。 |
| 中等复杂度逻辑 (涉及 1-2 个表的计算) |
模型(Model) | 如 Order::calculateTotal(),保持高内聚。 |
| 复杂业务 (涉及 3+ 个模型、第三方 API、事务) |
服务层(Service) | 分离关注点,避免模型变成“上帝对象”。 |
| 绝不 | 控制器 | 无论何时,都避免在控制器中写 SQL 或复杂 if。 |
行业通用准则(经验总结)
- 瘦控制器,胖模型 是基础,控制器绝对不写业务逻辑,只负责 HTTP 请求的输入输出。
- 业务逻辑与数据访问分离,如果你的
Model里既包含了验证、计算,又包含了对其他表的where查询,且代码超过 500 行,请考虑拆分为 Service + Repository 模式。 - 对于 Laravel 开发者:强烈建议利用 FormRequest(做请求参数校验) + Action/Service 类(做业务逻辑) + Model(做数据持久化),不要把校验逻辑写在控制器里,更不要写在模型中通过
$request->validate()直接调用。
一句话结论: 优先放 模型(Model);如果模型太大,则提升到 服务层(Service);永远不要写在 控制器 里。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播