在 yii2 中,自定义验证规则需通过 $model->adderror() 抛出错误信息,而非 return false 或 throw exception;方法须为 public 且接收 $attribute 和 $params 参数,支持占位符和国际化。

在 Yii2 中,自定义验证规则并抛出自定义错误信息,核心是让验证方法返回 false 或调用 $model->addError(),同时确保错误信息能被视图正确显示。不推荐直接 throw Exception,除非是程序异常(如数据库不可用),而非业务校验失败。
在模型中定义自定义验证方法
在模型类(如 UserForm)中添加一个 public 方法,方法名任意,但需在 rules() 中引用:
- 方法必须是 public,且接收两个参数:
$attribute(当前验证字段名)和$params(额外参数) - 方法内通过
$this->addError($attribute, '错误提示')添加错误,这是最标准、最可控的方式 - 不要 return false 替代 addError —— 它不会触发错误显示,仅中断验证链
示例:
public function rules()
{
return [
['username', 'validateUsernameUnique'], // 引用自定义方法
['age', 'validateAgeRange'],
];
}
<p>public function validateUsernameUnique($attribute, $params)
{
if ($this->hasErrors($attribute)) {
return;
}
$exists = User::find()->where(['username' => $this->username])->exists();
if ($exists) {
$this->addError($attribute, '用户名 "{value}" 已被注册。', ['{value}' => $this->username]);
}
}</p><p>public function validateAgeRange($attribute, $params)
{
if ($this->age age > 120) {
$this->addError($attribute, '年龄必须在 18 到 120 岁之间。');
}
}</p>使用 inline validator(匿名函数)快速验证
适合简单逻辑,无需复用的场景。注意:闭包中若要访问模型属性或调用 addError,需 use $this 并声明为引用:
- 闭包必须 use
&$this才能调用$this->addError() - 不能只写
use ($this)(PHP 不允许值传递 $this) - 错误消息支持占位符,如
{value}、{attribute}
示例:
public function rules()
{
return [
['email', function ($attribute, $params) {
if (!filter_var($this->$attribute, FILTER_VALIDATE_EMAIL)) {
$this->addError($attribute, '邮箱格式不正确。');
}
}],
['password', function ($attribute, $params) {
if (strlen($this->$attribute) addError($attribute, '密码长度不能少于 {length} 位。', ['{length}' => 6]);
}
}],
];
}在控制器中触发验证并检查结果
调用 $model->validate() 后,错误会自动存入模型。渲染视图时,ActiveForm 会自动显示这些错误:
- 确保视图中使用了
= $form->field($model, 'username') ?>,它会自动渲染错误 - 控制器中可手动检查是否有错误:
if (!$model->validate()) { /* 处理失败 */ } - 若需统一返回 JSON(如 API 场景),可提取错误:
$model->getFirstErrors()或$model->getErrors()
注意事项与常见坑
避免以下典型问题:
- 误用 return false:仅终止当前规则验证,不添加错误,前端看不到提示
- 忘记检查 hasErrors() 前置条件:如唯一性验证前先判断是否已有其他错误,避免重复查询
-
在验证方法中修改属性值:Yii2 验证默认不修改数据,如需预处理(如 trim),应在
beforeValidate()中做 -
国际化未生效:错误消息应通过
Yii::t()包裹,如Yii::t('app', '用户名已存在')











