yii2模型rules()支持四种自定义验证方式:一、内置验证器传参;二、模型内validate开头方法;三、匿名函数闭包;四、独立验证器类。

在 Yii2 中,模型的 rules() 方法支持自定义验证规则,既可以通过定义独立的验证方法,也可以使用匿名函数(PHP 7.4+ 推荐),还可复用内置验证器并传入自定义参数。关键在于:规则数组的第三项(即验证器配置)可接受键值对形式的额外参数,供验证器内部使用。
方式一:使用内置验证器 + 自定义参数
Yii2 内置验证器(如 required、string、in、match 等)均支持传入自定义选项。这些参数会自动注入到验证器实例中,并可在 validateAttribute() 或对应验证逻辑中通过 $this->xxx 访问。
例如,限制用户名只能包含字母、数字和下划线,且长度 3–16:
[
['username', 'match', 'pattern' => '/^[a-zA-Z0-9_]{3,16}$/', 'message' => '用户名格式不正确'],
]
再比如,动态指定允许的枚举值(从配置或数据库读取):
[
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE], 'strict' => true],
]
方式二:定义模型内验证方法(推荐用于复杂逻辑)
在模型类中写一个公共方法(命名需以 validate 开头,如 validateEmailUniqueness),然后在 rules() 中引用该方法名字符串:
- 方法签名必须为
public function validateXxx($attribute, $params) -
$params是规则中传入的关联数组,可用于传递开关、依赖字段、上下文等 - 验证失败时调用
$this->addError($attribute, $message)
示例:检查邮箱是否已存在,但跳过当前用户(更新场景):
public function rules()
{
return [
['email', 'validateEmailUniqueness', 'exceptCurrent' => true],
];
}
public function validateEmailUniqueness($attribute, $params)
{
$query = User::find()->where(['email' => $this->$attribute]);
if (!empty($params['exceptCurrent']) && $this->id) {
$query->andWhere(['!=', 'id', $this->id]);
}
if ($query->exists()) {
$this->addError($attribute, '该邮箱已被注册');
}
}
方式三:使用匿名函数(适合简单、一次性的校验)
Yii2 2.0.14+ 支持在 rules 中直接传入闭包(Closure),闭包接收两个参数:$model 和 $attribute。注意:闭包中无法直接访问 $params,如需参数应捕获使用 use。
[
['age', function ($model, $attribute) {
if ($model->$attribute $attribute > 150) {
$model->addError($attribute, '年龄必须在 0 到 150 之间');
}
}],
// 带参数的闭包(捕获外部变量)
['score', function ($model, $attribute) use ($minScore, $maxScore) {
if ($model->$attribute $attribute > $maxScore) {
$model->addError($attribute, "分数应在 {$minScore}–{$maxScore} 之间");
}
}],
]
补充说明:自定义验证器类(适合复用性要求高的场景)
若规则逻辑通用(如「手机号格式 + 归属地校验」「身份证号合法性 + 出生日期合理性」),建议封装为独立验证器类,继承 \yii\validators\Validator,重写 validateAttribute()。然后在 rules 中使用类名或配置数组引用:
use app\validators\ChineseIdValidator;
// ...
[
['idCard', ChineseIdValidator::class],
// 或带参数
['idCard', ChineseIdValidator::class, 'allow15' => false, 'checkBirth' => true],
]
此类中可通过 $this->allow15、$this->checkBirth 直接访问传入参数。











