应使用 validateScene() + 自定义 scene 方法动态切换验证规则:在模型中定义 sceneRegister()、sceneUpdate() 等方法,内部调用 $this->validate()->rule(...) 设置场景专属规则,并通过 $model->scene('register')->save($data) 显式触发;注意继承 think\Model、scene() 必须前置调用、方法名严格匹配且以 scene 开头、字段规则需按场景手动控制、unique 验证需排除主键。
验证规则在模型里写死,但业务要按场景换规则怎么办
ThinkPHP 的
属性默认是静态定义的,运行时没法直接改。硬编码多套规则(比如注册用一套、编辑用一套)会导致模型臃肿,且容易漏掉字段校验逻辑。
真正可行的做法是:**把验证规则从模型属性里抽出来,改用
+ 自定义场景方法控制**。
在模型中定义多个
方法(如
、
),每个方法里调用
动态设置规则
调用时显式传入场景名:
,否则默认走全局
属性
注意:动态规则不会自动合并到
属性里,所以别指望不调
就能触发它们
validateScene() 不生效?检查这三处硬性条件
常见现象是写了
方法,也调了
,但验证还是走默认规则或完全没触发。
模型必须继承
(不是
或其他基类)
必须在验证动作前调用,例如
,不能写成
场景方法名必须严格匹配传入的字符串,且必须以
开头(如
对应
),大小写敏感
字段级动态验证:比如“手机号只在注册时必填”
静态规则写法(
数组)无法表达“仅某场景下该字段参与验证”,得靠场景方法内部手动控制字段规则。
立即学习
“
PHP免费学习笔记(深入)
”;
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
示例:用户模型中,
字段只在注册时为
,编辑时允许为空:
每个
方法返回的是
实例,可链式调用
、
避免在多个场景中重复写相同字段规则,可先定义公共规则数组再
注意
验证的排除主键写法:
,否则编辑时会误判自己已存在
运行时切换规则集的性能和兼容性代价
动态规则本质是每次调用都新建
实例并解析规则,比静态
属性略慢,但对绝大多数业务无感。
TP6.0+ 支持闭包式规则定义,可用于更复杂的运行时判断(如根据用户角色开关字段)
TP5.1 中若用了
数组 +
,注意数组键名不能含点号(
会解析失败),得用下划线代替
第三方验证器(如自定义的
类)必须确保在场景方法中正确实例化并注册,否则
找不到规则
最易被忽略的是:场景方法返回的
实例,不会影响模型后续其他操作的默认验证行为——它只作用于当前这一次 save / create / validate 调用。想复用就得每次都显式调用
。
validatevalidateScene()scenesceneRegister()sceneUpdate()$this->validate()->rule(...)$model->scene('register')->save($data)validatevalidatescene()sceneEdit()scene('edit')think\Modelthink\db\Queryscene()$model->scene('xxx')->save(...)$model->save(...)->scene('xxx')scenesceneLoginscene('login')validatemobilerequirepublic function sceneRegister()
{
return $this->validate([
'mobile' => 'require|mobile',
'username' => 'require|unique:user',
]);
}
public function sceneUpdate()
{
return $this->validate([
'username' => 'unique:user,username^id',
// mobile 不在这里出现,即不校验
]);
}sceneXxx()Validaterule()message()array_merge()uniqueunique:table,field^pkValidatevalidatevalidatesceneuser.mobileMobileCheckvalidate()Validatescene()