Yii2多字段联合校验需用内联验证器、自定义方法或独立验证类:内联适合简单逻辑,规则为[['a','b'],function(){}];自定义方法需public且签名固定;独立类须继承Validator并重写validateAttribute()。

Yii2 中实现多字段联合校验,核心在于使用内联验证器(inline validator)或独立验证类,针对多个属性之间的逻辑关系做判断,比如“当 A 为某值时 B 必填”“两个字段至少填一个”“密码与确认密码必须一致”等。
用内联验证器做多字段联合校验
适合一次性、逻辑不复杂、仅在当前模型使用的场景。直接在 rules() 中定义匿名函数或回调方法,签名必须为 function($model, $attribute, $params)。
- 验证逻辑可自由访问任意属性,例如
$model->fieldA和$model->fieldB - 失败时调用
$model->addError($attribute, $message),不能 return false 或 throw 异常 - 若字段允许为空(没加 required),默认仍会执行;如需跳过空值,需手动判断:
if (empty($model->$attribute)) return; - 规则写法必须是数组形式:
[['fieldA', 'fieldB'], function() {...}]或[['fieldA', 'fieldB'], [$this, 'checkBoth']],不能只写字符串
示例:要求 card_id 和 card_code 至少填一个:
public function rules()
{
return [
[['card_id', 'card_code'], function ($model, $attribute, $params) {
if (empty($model->card_id) && empty($model->card_code)) {
$model->addError($attribute, 'card_id 或 card_code 至少填写一项');
}
}, 'skipOnEmpty' => false],
];
}
用自定义方法名做联合校验
把验证逻辑抽成模型内的 public 方法,更清晰易读,也方便复用(同一模型内)。
- 方法必须是
public,且签名固定:public function methodName($attribute, $params) - 规则中引用格式为:
['fieldA', 'methodName'],注意不是字符串回调,而是规则别名 - 若校验依赖多个字段,可在方法体内直接访问其他属性,无需额外传参
- 建议配合
'skipOnEmpty' => false使用,避免空值被跳过导致逻辑失效
示例:当 status == 1 时,reason 必须非空:
public function rules()
{
return [
['reason', 'validateReasonRequiredWhenStatusOne', 'skipOnEmpty' => false],
];
}
public function validateReasonRequiredWhenStatusOne($attribute, $params)
{
if ($this->status == 1 && empty($this->reason)) {
$this->addError($attribute, '状态为 1 时,原因必填');
}
}
用独立验证类处理复杂联合逻辑
适合跨模型、含数据库查询、正则匹配、多字段强耦合或需被多个模型复用的场景。
- 新建类继承
yii\validators\Validator,重写validateAttribute() - 类名必须以
Validator结尾(如TwoFieldDependValidator),否则自动加载失败 - 在
init()中调用parent::init(),确保$this->message等属性可用 - 参数通过 public 属性声明(如
public $dependOn = 'status';),并在 rules 中传入 - 如需支持客户端验证,还需实现
clientValidateAttribute()返回 JS 字符串
示例:检查 senderId 和 receiverId 是否都存在于 User 表中:
class UserPairExistValidator extends Validator
{
public $targetClass = 'app\models\User';
public function validateAttribute($model, $attribute)
{
$ids = [$model->senderId, $model->receiverId];
$exists = $this->targetClass::find()
->where(['id' => $ids])
->count();
if ($exists !== 2) {
$model->addError($attribute, '发送者和接收者都必须是有效用户');
}
}
}
在 rules 中使用:
public function rules()
{
return [
[['senderId', 'receiverId'], 'app\validators\UserPairExistValidator'],
];
}
注意事项与常见避坑点
多字段联合校验容易因配置疏漏导致静默失效,开发时务必检查以下几点:
- 内联函数或自定义方法未声明为
public,调用失败且无报错提示 - 忘记加
'skipOnEmpty' => false,导致空字段被跳过,联合逻辑不触发 - addError 的第一个参数误写为固定字段名(如
'reason'),但实际规则绑定的是['fieldA', 'fieldB']数组,此时应传入$attribute或任一关键字段名 - 规则中指定多个字段(如
['a', 'b']),但验证方法只校验了其中一个,遗漏逻辑覆盖 - 独立验证类未实现
validateAttribute(),而错误写了validate()—— Yii2 不会调用它


















