yii的mvc是围绕请求生命周期形成的职责闭环:controller仅调度和组装参数,model承载数据与验证(activerecord专用于表映射),view专注渲染,业务逻辑应抽离至service层。

Yii 的 MVC 不是教科书式抽象分层,而是围绕请求生命周期形成的职责闭环:请求进来走 Controller → 业务逻辑交给 Service 或 Model → 数据持久化由 ActiveRecord 或 Repository 承担 → 视图只做渲染,不掺逻辑。
Controller 必须严格遵循命名与路由规则
控制器类名必须以 Controller 结尾、首字母大写,且继承 yii\web\Controller;方法名必须以 action 开头、后接驼峰式动作 ID(如 actionUserList)。否则路由匹配失败,直接 404。
-
index.php?r=user/list对应的是UserController::actionList(),不是user/list路径字面意思 - 控制器命名空间默认为
app\controllers,若改用模块(如api),需在模块类中显式设置$this->controllerNamespace - 不要在
Controller中写数据库查询或复杂计算——它只负责“调度”和“组装参数”
Model 不等于 ActiveRecord,但 ActiveRecord 是 Model 最常用实现
Yii 中的 Model 是泛指数据载体与验证逻辑,而 ActiveRecord 是其子类,专用于映射数据库表。两者常被混用,但语义不同:
- 表单验证、API 入参校验用
yii\base\Model子类(如LoginForm) - 操作真实数据表时才用
yii\db\ActiveRecord子类(如User),它自带find()、save()、delete() -
ActiveRecord::tableName()必须返回字符串,不能是变量或表达式;若表名含前缀或大小写敏感,必须覆写该方法
View 渲染路径由 Controller ID 自动推导,不可硬编码
调用 $this->render('index') 时,Yii 默认查找 @app/views/[controller-id]/index.php。比如 SiteController 调用 render('about'),实际加载的是 @app/views/site/about.php。
- 视图文件名不带
.php后缀,传给render()的是纯名称 - 若想复用视图(如多个控制器共用一个列表模板),可用别名路径:
$this->render('@app/views/shared/_list', [...]) - 避免在视图里调用
Yii::$app->db或执行 SQL —— 这会破坏分层,也难测试
常见分层越界错误:把 Service 当 Controller 用
很多新手把业务逻辑全塞进 Controller,或反过来,在 Model 里写发邮件、调第三方 API、处理文件上传等非数据职责。正确做法是抽离为独立 Service 类,通过依赖注入使用:
- Service 类不继承任何框架基类,只专注单一职责(如
OrderPaymentService) - 在 Controller 中用
Yii::createObject(OrderPaymentService::class)或 DI 容器获取实例 - Service 内部可调用多个 Model 或 Repository,但绝不直接 echo 或 redirect —— 控制流仍归 Controller 管
真正容易被忽略的,是 Service 层没有强制目录约束,导致团队随意建文件夹、命名混乱。建议统一放在 @common/services/ 下,并在 common/config/bootstrap.php 中注册自动加载,否则上线后可能报类找不到。











