save() 默认静默失败只返回 false,不抛异常;需主动检查 geterrors()、beforesave() 返回值、rules 字段存在性及场景匹配,否则易因验证过滤或逻辑遗漏导致无错误提示的保存失败。

因为 save() 本就不抛异常,返回 false 是正常行为,不是 bug —— 你得主动查 $model->getErrors() 才能看到原因。
save() 默认静默失败,不 throw 任何异常
这是 Yii2 的设计选择:写库失败时只返回 false,不会中断执行流。很多人误以为“没报错 = 成功”,结果数据根本没进库。
- 必须显式判断返回值:
if (!$model->save()) { var_dump($model->getErrors()); } - 别依赖
try-catch捕获 save() 异常——它根本不会抛 - 例外情况:事务中某步失败导致 rollback,但 save() 本身仍只返 false,错误在事务层
beforeSave() 返回 false 或没 return,直接中断保存
重写 beforeSave() 时最容易踩坑:漏掉 return parent::beforeSave($insert);,或逻辑分支里某个路径没 return,都会让 save() 静默返回 false,且 $model->getErrors() 为空。
- 错误写法:
public function beforeSave($insert) { parent::beforeSave($insert); }(没 return) - 正确写法:
public function beforeSave($insert) { return parent::beforeSave($insert); } - 带自定义逻辑时,所有分支都必须有 return,例如:
if ($this->status === 'draft') { return false; } return parent::beforeSave($insert);
rules 里写了不存在的字段,验证失败却不提示
比如 rules() 中写了 ['password2', 'required'],但数据库表没有 password2 字段,验证会失败,$model->getErrors() 却可能为空——因为该字段被当成“安全属性”过滤掉了,没进验证流程。
- 检查
$model->scenario是否包含该字段,或是否在safeAttributes()中声明 - 更常见的是:用
$model->load()时传入了未声明为safe的字段,导致赋值失败,后续 save() 因缺必填字段而失败 - 调试时加一句:
var_dump($model->attributes);看实际加载了哪些字段
场景(scenario)不匹配导致字段被忽略
如果模型用了场景(如 'update'),而新字段没放进对应场景的 rules,即使赋了值也会被过滤,save() 因缺失 required 字段返回 false,但 getErrors() 可能不显示——因为那个字段压根没参与验证。
- 确认当前场景:
echo $model->scenario; - 检查 rules 数组里,目标字段是否在对应场景下声明,例如:
['title', 'required', 'on' => 'create'] - 临时绕过验证调试可用
$model->save(false),但仅限排查,不可用于生产表单
最麻烦的情况是:save() 返回 false,getErrors() 为空,beforeSave() 又没日志——这时候得在 beforeSave() 开头加 file_put_contents('/tmp/yii-debug.log', print_r($this->attributes, 1), FILE_APPEND);,否则真找不到断在哪一步。











