yii2自定义规则需设'skiponempty'=>false并配合when控制空值校验;方法内须主动判空处理,内联验证器需加守卫,独立验证类init()须调用parent::init()。

Yii2 自定义规则默认会跳过空值(skipOnEmpty === true),但很多业务场景要求“即使为空也要校验”,比如条件必填、空值非法、或需统一返回提示。关键不是绕开空值,而是明确控制何时执行、何时响应。
空值是否触发验证,由 skipOnEmpty 和 when 共同决定
Yii2 的验证流程中,skipOnEmpty 只在 when 返回 true 后才起作用。也就是说:
- 若
when返回false,整条规则直接跳过,skipOnEmpty不生效 - 若
when返回true,再看skipOnEmpty:为true且属性为空 → 跳过;为false→ 强制执行校验逻辑
所以,要让空值也走自定义方法,最稳妥写法是显式设 'skipOnEmpty' => false:
['reason', 'validateReasonRequired', 'skipOnEmpty' => false, 'when' => function ($model) {
return $model->status === 1;
}]
自定义方法内部仍需判断空值并主动处理
即使设置了 skipOnEmpty => false,方法体里也不能假设值一定非空。应按业务语义决定“空”算错误还是合法:
- 若“空”本身不合法(如字段不允许为空字符串):
if ($this->reason === '' || $this->reason === null) { $this->addError('reason', '原因不能为空'); } - 若仅在特定条件下空值才非法(如 status=1 时 reason 必填):
if ($this->status === 1 && empty($this->reason)) { $this->addError('reason', '状态为1时,原因必填'); }
内联验证器对空值更敏感,需手动守卫
内联验证器(匿名函数或 [$this, 'method'])默认不跳过空值 —— 但这是假象。实际行为取决于它挂载的规则是否带 required 或其它前置校验。一旦前置规则失败(例如字段为空且有 required 规则),Yii2 默认不再执行后续规则(含内联)。因此:
- 务必搭配
'skipOnEmpty' => false和'skipOnError' => false,确保不被跳过 - 在函数体内第一行加空值判断,避免
$this->xxx报 Notice:if (empty($model->$attribute)) { return; } // 或按需报错
独立验证类中,init() 和 validateAttribute() 都要兼顾空逻辑
继承 yii\validators\Validator 的类,需在 init() 中调用 parent::init(),否则 $this->skipOnEmpty 等属性未初始化,行为不可控。在 validateAttribute() 中,空值处理逻辑和内联类似:
- 读取
$this->skipOnEmpty判断是否应跳过(但通常已由框架处理) - 业务上需区分“跳过”和“报错”:空字符串可能是有效值(如可选备注),也可能是非法输入(如手机号不能为空)
- 推荐统一用
empty($value)判定,而非仅=== '',覆盖null、0、false等常见空情形











