yii2中自定义验证规则有两种方式:一是在模型中定义validate开头的方法,适用于简单、单模型校验;二是创建继承validator的独立验证器类,适合复用和复杂逻辑;还可通过clientvalidateattribute支持客户端校验。

在 Yii2 中,自定义验证规则是处理特殊业务校验(比如限定数字范围、校验手机号格式、判断是否为有效年份等)的常用方式。当内置规则(如 number、integer、double)无法满足需求时,推荐通过 模型中的自定义验证方法 或 独立验证器类 实现。
一、在模型中定义验证方法(最常用)
适合逻辑简单、仅用于当前模型的校验,例如要求参数必须是 100~999 之间的整数:
- 在模型类(如
UserForm)中添加一个 public 方法,命名需以validate开头,如validateScore - 在
rules()中引用该方法名(不带validate前缀),并指定对应属性 - 方法内部使用
$this->addError($attribute, $message)添加错误
示例代码:
public function rules()
{
return [
['score', 'validateScore'], // 调用 validateScore() 方法
// 其他规则...
];
}
public function validateScore($attribute, $params)
{
$value = $this->$attribute;
if (!is_numeric($value) || $value 999 || floor($value) != $value) {
$this->addError($attribute, '分数必须是 100 到 999 之间的整数');
}
}
二、创建独立验证器类(复用性强)
适合多模型共用、逻辑较复杂或需配置参数的场景,例如校验“是否为正偶数”:
- 新建类文件,如
app\validators\EvenValidator.php - 继承
\yii\validators\Validator,重写validateAttribute() - 可在构造时传入配置(如
min、allowZero),增强灵活性
示例:
namespace app\validators;
use yii\validators\Validator;
class EvenValidator extends Validator
{
public $min = 0;
public function validateAttribute($model, $attribute)
{
$value = $model->$attribute;
if (!is_numeric($value) || $value min || $value % 2 !== 0) {
$this->addError($model, $attribute, '{attribute} 必须是大于等于 {min} 的正偶数', ['min' => $this->min]);
}
}
}
在模型中使用:
public function rules()
{
return [
['age', app\validators\EvenValidator::class, 'min' => 2],
];
}
三、配合客户端验证(可选但推荐)
若希望表单提交前在浏览器端也做基础校验,可覆写验证器的 clientValidateAttribute() 方法,返回 JavaScript 校验逻辑:
- 返回 JS 字符串,其中
attribute是字段名,value是当前值 - 需确保与服务端逻辑一致,避免绕过校验
- 注意:仅对支持 JS 的浏览器生效,不能替代服务端验证
例如在 EvenValidator 中追加:
public function clientValidateAttribute($model, $attribute, $view)
{
$min = $this->min;
return message ?: "$attribute 必须是正偶数"}');
}
JS;
}
四、常见数字校验场景速查
以下是一些高频需求的实现要点:
-
手机号开头校验:用
preg_match('/^1[3-9]\d{9}$/', $value)配合自定义方法 -
金额精度控制:用
bcadd($value, '0', 2)或正则/^\d+(\.\d{1,2})?$/确保最多两位小数 - 年份范围校验:检查是否为 4 位数字且在合理区间(如 1900–2100)
-
非负整数:直接用内置规则
['age', 'integer', 'min' => 0]即可,无需自定义
不复杂但容易忽略的是:所有自定义验证都应在服务端执行,客户端仅为体验优化;数字类型务必先用 is_numeric() 或强制转换(如 (int)$value)预处理,防止字符串参与运算出错。











