Yii2自定义验证需设'skipOnEmpty'=>false和'skipOnError'=>false确保始终执行;内联验证需手动判空;独立验证类需在init()调用parent::init();客户端验证需额外实现clientValidateAttribute()。

Yii2 自定义验证中,若想让规则不被默认的空值或错误状态跳过,关键不是“关闭默认参数验证”,而是显式控制验证触发条件。框架默认对空值(skipOnEmpty)和已有错误(skipOnError)会跳过后续验证,这常导致自定义逻辑不执行——尤其在字段非必填、或依赖其他字段状态时。
让自定义验证始终执行
只需在规则数组中强制关闭跳过机制:
-
'skipOnEmpty' => false:即使字段为空(如null、空字符串),也执行你的验证逻辑 -
'skipOnError' => false:即使该字段已在前面规则中报错(比如required失败),仍继续运行你的方法
示例:
public function rules()
{
return [
[['status'], 'validateStatusDependsOnRole', 'skipOnEmpty' => false, 'skipOnError' => false],
];
}
public function validateStatusDependsOnRole($attribute, $params)
{
if ($this->role === 'admin' && !in_array($this->$attribute, ['active', 'pending'])) {
$this->addError($attribute, '管理员只能设为 active 或 pending');
}
}
内联验证器要手动判空
如果用匿名函数写内联验证,skipOnEmpty => false 会让空值也进函数,但你可能不希望空值参与逻辑判断。此时需在函数体内主动处理:
- 检查是否为空:
if ($this->$attribute === null || $this->$attribute === '') { return; } - 避免对空值做非法操作(比如调用
strlen()、in_array()等)
例如校验手机号格式时,空值直接放过,非空才走正则:
['mobile', function ($model, $attribute, $params) {
$value = $model->$attribute;
if ($value === null || $value === '') {
return;
}
if (!preg_match('/^1[3-9]\d{9}$/', $value)) {
$model->addError($attribute, '手机号格式不正确');
}
}]
独立验证类里控制初始化行为
写独立验证类(如 StatusValidator)时,skipOnEmpty 和 skipOnError 是父类已支持的属性,可直接在 rules() 中传入,无需重写逻辑:
- 类中不用手动判断空值,框架会根据
$this->skipOnEmpty的值决定是否调用validateAttribute() - 若你设了
'skipOnEmpty' => false,框架就会把空值也传进来,你再在validateAttribute()里按需处理 - 记得在
init()中调用parent::init(),否则这些属性不会生效
注意客户端验证不自动同步
以上设置只影响服务端验证。自定义方法默认不支持客户端 JS 校验,表单失去焦点时不会触发。如需实时反馈,必须额外实现 clientValidateAttribute() 方法并返回合法 JS 字符串,或改用 AJAX 验证模式。


















