Yii2模型自定义参数验证核心是重写rules()方法并结合自定义验证器(内联方法或独立类),支持客户端与服务端双校验,需掌握规则结构、验证器注册、错误提示及参数传递。

Yii2 中模型的自定义参数验证,核心是重写 rules() 方法并结合自定义验证器(可复用类或匿名函数),同时支持客户端 + 服务端双校验。关键在于理解验证规则结构、验证器注册方式、错误提示控制以及如何传参给验证逻辑。
基础:在 rules() 中定义自定义验证规则
Yii2 允许在 rules() 返回数组中使用字符串、数组或闭包形式注册验证器。最常用的是数组形式,指定字段、验证器类名(或内置别名)、附加选项:
-
字段名:要验证的属性,如
'username' -
验证器:可以是内置别名(
'required'、'string'),也可以是自定义类名(如'validatePasswordStrength')或完整类路径 -
额外选项:如
'on' => ['register'](场景)、'message' => '密码太弱'、'skipOnEmpty' => false等
方式一:使用模型内联方法(推荐快速验证)
适合逻辑简单、仅当前模型使用的验证。在模型类中定义一个 public 方法,方法名即为规则中指定的验证器名:
public function rules()
{
return [
['password', 'validatePasswordStrength'],
['email', 'email', 'message' => '邮箱格式不正确'],
];
}
public function validatePasswordStrength($attribute, $params)
{
$value = $this->$attribute;
if (strlen($value) < 8 || !preg_match('/[A-Z]/', $value) || !preg_match('/[0-9]/', $value)) {
$this->addError($attribute, '密码至少8位,需包含大写字母和数字');
}
}
注意:addError() 必须显式调用,否则不会显示错误;该方法自动接收 $attribute 和 $params(来自 rules 中的额外键值对)。
方式二:独立验证器类(推荐复用与解耦)
创建继承 yiialidatorsValidator 的类,支持复用、配置化和客户端验证:
// @app/validators/StrongPasswordValidator.php
namespace appalidators;
use yiialidatorsValidator;
class StrongPasswordValidator extends Validator
{
public $minLength = 8;
public $requireUpper = true;
public $requireDigit = true;
public function validateAttribute($model, $attribute)
{
$value = $model->$attribute;
$errors = [];
if (strlen($value) < $this->minLength) {
$errors[] = "长度不能少于 {$this->minLength} 位";
}
if ($this->requireUpper && !preg_match('/[A-Z]/', $value)) {
$errors[] = '必须包含大写字母';
}
if ($this->requireDigit && !preg_match('/[0-9]/', $value)) {
$errors[] = '必须包含数字';
}
if (!empty($errors)) {
$model->addError($attribute, implode(';', $errors));
}
}
// 可选:支持 JS 客户端验证(需配合 ActiveForm)
public function clientValidateAttribute($model, $attribute, $view)
{
$options = [
'minLength' => $this->minLength,
'requireUpper' => $this->requireUpper ? 'true' : 'false',
'requireDigit' => $this->requireDigit ? 'true' : 'false',
];
$js = <<<JS
if (value.length < {$this->minLength}) {
messages.push('长度不能少于 {$this->minLength} 位');
}
if ({$this->requireUpper} && !/[A-Z]/.test(value)) {
messages.push('必须包含大写字母');
}
if ({$this->requireDigit} && !/[0-9]/.test(value)) {
messages.push('必须包含数字');
}
JS;
return $js;
}
}
在模型中使用:
use appalidatorsStrongPasswordValidator;
public function rules()
{
return [
['password', StrongPasswordValidator::class, 'minLength' => 10],
// 或简写为字符串路径:['password', 'app\validators\StrongPasswordValidator']
];
}
方式三:匿名函数验证(适合一次性轻量逻辑)
无需额外文件,适合临时、简单、无复用需求的校验:
public function rules()
{
return [
['age', function ($attribute, $params) {
if ($this->$attribute < 0 || $this->$attribute > 150) {
$this->addError($attribute, '年龄必须在 0~150 之间');
}
}],
];
}
注意:匿名函数无法支持客户端验证,且不利于单元测试和复用,仅建议用于调试或极简场景。
补充:验证场景(scenario)与条件验证
通过 'on' 指定场景,或用 'when' 动态控制是否触发验证:
[
['email', 'required', 'on' => ['register', 'reset']],
['email', 'required', 'when' => function ($model) {
return $model->type === 'user';
}]
]
场景需在模型中提前声明:public function scenarios() { return ['register' => ['username', 'email', 'password']]; }
掌握这几种方式,就能灵活覆盖 Yii2 中绝大多数自定义验证需求——重点是按复杂度选型:单次用内联方法,通用用独立类,极简用闭包,再配好场景和提示语,验证就稳了。


















