最轻量注册验证规则用Validator::extend()闭包,但复用难;推荐自定义FormRequest类+抽象基类,或实现Rule接口的独立验证类,兼顾可测性、可维护性与场景动态适配。

直接用 Validator::extend() 注册闭包最轻量,但跨项目复用难;真要封装,优先走自定义 FormRequest 类 + 抽象基类路线,而不是硬塞一堆 Validator::extend()。
用 Validator::extend() 写闭包规则,适合一次性、简单逻辑
比如验证手机号是否以 13/15/18 开头:
Validator::extend('cn_mobile', function ($attribute, $value, $parameters) {
return preg_match('/^1[358]\d{9}$/', $value);
});
注意三点:
- 必须同时在语言文件
resources/lang/en/validation.php或messages()方法里加错误提示,否则报错时显示The :attribute is invalid. - 闭包里不能直接访问
$this,没法调用模型或服务,复杂校验(如查库、调 API)不适合放这里 - 多个项目共用时,得重复粘贴注册代码,容易漏掉或版本不一致
封装成独立验证类,适合复用、可测试、带上下文
新建 app/Validation/Rules/CnMobileRule.php:
namespace App\Validation\Rules;
use Illuminate\Contracts\Validation\Rule;
class CnMobileRule implements Rule
{
public function passes($attribute, $value)
{
return preg_match('/^1[358]\d{9}$/', $value) === 1;
}
public function message()
{
return '手机号格式不正确。';
}
}
控制器或 FormRequest 中直接用:
'phone' => ['required', new CnMobileRule]
优势很明显:
- 类可被
phpunit单独测试,闭包做不到 - 支持构造参数,比如
new CnMobileRule($countryCode) - 错误消息写在类里,不依赖语言文件,迁移成本低
在 FormRequest 里动态组合规则,适合多场景复用同一请求类
比如一个 UpdateProfileRequest 要适配「普通用户」和「企业用户」两种提交路径:
public function rules()
{
$base = [
'name' => 'required|string|max:50',
'avatar' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
];
if ($this->routeIs('api.enterprise.*')) {
return array_merge($base, [
'company_name' => 'required|string',
'license_no' => 'required|unique:enterprises',
]);
}
return $base;
}
关键点:
- 别把所有规则堆进一个大数组,用
$this->routeIs()、$this->isMethod('PUT')或$this->user()?->isEnterprise()动态判断 - 避免在
rules()里做 DB 查询,性能差;查库逻辑应放到withValidator()或单独服务里 - 如果规则分支太多,建议拆成
UpdatePersonalProfileRequest和UpdateEnterpriseProfileRequest,别强求“一个类打天下”
扩展 Validator 类本身,适合全局统一行为(慎用)
比如所有 unique 规则默认忽略软删除记录:
Validator::extend('unique_soft', function ($attribute, $value, $parameters, $validator) {
$table = $parameters[0];
$column = $parameters[1] ?? 'id';
return DB::table($table)->where($column, $value)->withoutTrashed()->count() === 0;
});
但更稳妥的做法是:
- 用
Rule::unique('users')->ignoreSoftDeleted()(Laravel 9+) - 或封装一个
UniqueSoftRule类,而不是污染全局Validator - 一旦扩展了
Validator,升级 Laravel 时容易因底层变更挂掉,维护成本高
真正需要封装的不是“怎么写规则”,而是“怎么让规则随业务场景自动切换、可测、不散落”。闭包适合临时补丁,类规则适合长期维护,FormRequest 基类才是中大型项目里最常被忽略又最关键的封装层。


















