$model->save()返回false时,应立即调用$model->geterrors()获取验证错误;若为空,则需检查beforesave返回值、数据库完整性异常或场景配置问题。

Yii2中$model->save()返回false时如何看到具体错误
直接调用 $model->save() 返回 false,不代表没执行验证或没报错,而是框架把错误藏在了模型内部。不主动检查,永远不知道哪条规则失败。
关键动作只有一行:$model->getErrors()。它返回一个关联数组,格式如 ['username' => ['用户名不能为空']],是定位问题的唯一可靠入口。
- 必须在
save()后立刻调用,不能隔行或放到其他分支里 - 如果用
save(false)跳过验证,getErrors()永远为空——这不是 bug,是你关掉了校验开关 - 控制器中建议这样写:
if (!$model->save()) { \Yii::error($model->getErrors(), 'model-save-fail'); return $this->render('form', ['model' => $model]); }
为什么var_dump($model->getErrors())什么也没输出
常见原因是模型没触发验证流程。比如你手动赋值后直接 save(),但没调用 validate(),且模型配置了 scenarios() 或字段没进默认场景,save() 就会跳过验证、直接写库失败、返回 false,但 getErrors() 仍是空。
- 确认
rules()中对应字段有定义,且该字段在当前scenario下是活跃的(例如default场景未显式声明时,只包含rules()里带on的规则) - 检查是否误用了
save(false)—— 它绕过所有验证,只做数据写入,失败时也不填充 errors - 查看日志:开启
log组件后,\Yii::error($model->errors)可能比 var_dump 更早暴露空数组事实
数据库层面失败却没进getErrors()怎么办
getErrors() 只管模型层验证,不管数据库约束(如唯一索引冲突、外键拒绝、字段超长)。这类失败会抛出 \yii\db\IntegrityException 或类似异常,但被 save() 吞掉后也只返回 false。
- 加 try-catch 捕获底层异常:
try { $model->save(); } catch (\yii\db\IntegrityException $e) { \Yii::error($e->getMessage(), 'db-integrity'); // 解析 $e->getMessage() 找关键词,比如 'Duplicate entry' 或 'Cannot add or update a child row' - 启用
enableSchemaCache可能掩盖字段长度限制报错,临时关闭它有助于暴露真实 SQL 错误 - 检查数据库日志(如 MySQL 的
slow_query_log或 general log),确认 INSERT/UPDATE 语句是否真发出去了
调试时发现$errors是空数组但save还是false
这大概率是事务或事件中断导致的。Yii2 的 save() 内部会触发 beforeSave、afterSave 等事件,任何一个事件处理器返回 false,整个保存流程就终止,且不往 errors 里塞东西。
- 检查模型中是否重写了
beforeSave(),并可能在某些条件下写了return false; - 检查是否绑定了全局行为(Behavior),其
events()返回了EVENT_BEFORE_SAVE => function() { return false; } - 最简单验证法:临时注释掉所有自定义事件和行为,再试一次
save()
真正卡住的地方往往不在验证规则里,而在你忘了自己写的 beforeSave 或事务 rollback 条件里。











