Yii2控制器手动验证需三步:先用load()加载数据,再配置规则确保自定义验证执行(如skipOnEmpty=>false),最后检查$errors而非依赖异常;场景生效须同时满足定义scenarios()、rules中指定on、控制器设置scenario。

在 Yii2 控制器里手动验证自定义参数,关键不是“调用 validate() 就完事”,而是要明确:模型没加载数据,验证就无从谈起;规则没匹配场景或条件,验证就可能跳过;错误不检查$errors,就等于没验证。
先让参数进模型:load() 是必经步骤
控制器中不能直接对裸数组做 validate()。必须先把请求参数塞进模型实例:
- 普通表单(
application/x-www-form-urlencoded):用$model->load($request->post()),默认按模型的formName()匹配字段前缀 - JSON 接口(
application/json):需先解析原始体:$data = \yii\helpers\Json::decode($request->getRawBody());,再调$model->load($data, '')(第二个参数传空字符串,绕过 formName 匹配) - 手动赋值也行:
$model->attr1 = $data['attr1'] ?? null;,但要注意安全过滤和批量赋值风险
确保自定义规则真正执行
很多自定义方法(如 validateCountry() 或内联函数)默认会跳过空值或已有错误。若你希望它一定运行,得显式关掉跳过逻辑:
- 在 rules 中加配置:
['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false] - 内联验证器里也要主动判断:
if (empty($model->$attribute)) { return; }—— 这句不是可选,是控制是否继续校验的开关 - 独立验证类中,
$this->skipOnEmpty和$this->skipOnError同样需要留意,默认值不同,别混淆
验证后必须看 errors,而不是靠异常
Yii2 的 validate() 永远返回布尔值,失败时不会抛异常,错误信息全存在 $model->errors 里:
- 检查是否有错:
if (!$model->validate()) { var_dump($model->errors); } - 获取单个字段首个错误:
$model->getFirstError('country') - 返回 JSON 接口时,建议统一格式:
return ['success' => false, 'errors' => $model->errors];
场景(scenario)生效三要素缺一不可
如果用了场景但规则没触发,大概率卡在这三个地方:
- 模型中必须定义
scenarios()方法,明确列出该场景包含哪些属性(哪怕只是复制 default) - rules 中对应条目要写
'on' => 'xxx',否则只在 default 场景生效 - 控制器里必须手动设
$model->scenario = 'xxx',不能依赖构造参数或配置自动识别











