自定义验证方法未执行,主因是规则未挂载或调用链中断:字段名需与属性名完全一致;数据须经load()成功加载;场景配置须匹配rules()中'on'条件;方法须为public且仅含$attribute、$params两参数;空值或前置错误默认跳过验证,需设'skiponempty'=>false和'skiponerror'=>false。

自定义验证方法拿不到参数,通常不是写法错,而是调用链断了——Yii2根本没走到你的方法里。
检查验证规则是否真正挂载
规则写在 rules() 里,但必须满足三个条件才会触发:
- 字段名和模型属性名完全一致(大小写、下划线都不能差)
- 该字段数据已通过
$model->load($request->post())成功加载;如果load()返回false却没检查,后续validate()就像在空模型上运行 - 没设场景(
scenario),或设了但rules()里没配'on' => 'xxx',或没在控制器中执行$model->scenario = 'xxx'
确认方法签名和可见性
自定义验证方法必须严格满足:
- 访问修饰符是
public(protected或private会被跳过) - 方法名任意,但参数只能有两个:
$attribute(字符串,对应规则中字段名)和$params(数组,含规则配置项) - 不能多参、少参、类型不对,也不能加默认值(如
$params = [])
例如正确写法:public function checkMobile($attribute, $params) { ... }
错误写法:public function checkMobile($attribute, $params = []) 或 private function checkMobile(...)
验证是否被跳过:空值与错误状态
即使方法存在且签名正确,也可能被框架自动跳过:
- 字段值为空(
''、null、[])时,默认会跳过验证——除非显式设置'skipOnEmpty' => false - 同一字段已在前面的规则中报错(比如必填没过),默认也会跳过后续规则——需加
'skipOnError' => false - 所以完整写法应类似:
[['mobile'], 'checkMobile', 'skipOnEmpty' => false, 'skipOnError' => false]
快速定位:加日志或断点看是否执行
别只盯着返回值,先确认方法有没有被调用:
- 在自定义方法第一行加
\Yii::info("checkMobile called for {$attribute}"); - 提交表单后查
runtime/logs/app.log,没日志=根本没进方法 - 有日志但
$attribute是空或$params是空数组?说明规则配置漏传参数,比如写成了'checkMobile'而不是['checkMobile', 'someOption' => true]











