本文目录导读:

在PHP项目中统一进行请求参数校验,通常有几种方案,我推荐几种从简单到完善的实现方式:
基础方案:使用验证器类
创建一个统一的验证器基类:
<?php
class Validator
{
protected array $errors = [];
public function validate(array $data, array $rules): bool
{
$this->errors = [];
foreach ($rules as $field => $ruleSet) {
$value = $data[$field] ?? null;
$this->validateField($field, $value, $ruleSet);
}
return empty($this->errors);
}
protected function validateField(string $field, $value, array $rules): void
{
foreach ($rules as $rule) {
$params = [];
if (is_string($rule) && str_contains($rule, ':')) {
[$rule, $paramStr] = explode(':', $rule, 2);
$params = explode(',', $paramStr);
}
$method = 'rule' . ucfirst($rule);
if (method_exists($this, $method)) {
if (!$this->$method($field, $value, $params)) {
$this->errors[$field][] = $this->getErrorMessage($field, $rule, $params);
break;
}
}
}
}
protected function ruleRequired(string $field, $value, array $params): bool
{
return $value !== null && $value !== '';
}
protected function ruleEmail(string $field, $value, array $params): bool
{
return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
}
protected function ruleMin(string $field, $value, array $params): bool
{
$minLength = (int) $params[0];
return strlen($value) >= $minLength;
}
protected function ruleMax(string $field, $value, array $params): bool
{
$maxLength = (int) $params[0];
return strlen($value) <= $maxLength;
}
protected function ruleNumeric(string $field, $value, array $params): bool
{
return is_numeric($value);
}
protected function ruleInteger(string $field, $value, array $params): bool
{
return filter_var($value, FILTER_VALIDATE_INT) !== false;
}
protected function ruleIn(string $field, $value, array $params): bool
{
return in_array($value, $params);
}
protected function getErrorMessage(string $field, string $rule, array $params): string
{
$messages = [
'required' => "{$field} 字段是必填的",
'email' => "{$field} 格式不正确",
'min' => "{$field} 最少需要 {$params[0]} 个字符",
'max' => "{$field} 最多允许 {$params[0]} 个字符",
'numeric' => "{$field} 必须是数字",
'integer' => "{$field} 必须是整数",
'in' => "{$field} 必须是以下值: " . implode(', ', $params),
];
return $messages[$rule] ?? "{$field} 验证失败";
}
public function getErrors(): array
{
return $this->errors;
}
}
// 具体的业务验证器
class UserValidator extends Validator
{
public function validateCreate(array $data): bool
{
$rules = [
'username' => ['required', 'min:3', 'max:20'],
'email' => ['required', 'email'],
'age' => ['required', 'integer', 'min:1', 'max:150'],
'role' => ['required', 'in:admin,user,guest']
];
return $this->validate($data, $rules);
}
}
进阶方案:使用中间件 + 请求类
创建请求验证中间件:
<?php
// middleware/ValidationMiddleware.php
class ValidationMiddleware
{
public function handle($request, $next)
{
$routeName = $request->getRouteName();
$validatorClass = $this->getValidatorForRoute($routeName);
if ($validatorClass) {
$validator = new $validatorClass();
if (!$validator->validate($request->all())) {
// 统一返回格式
return response()->json([
'code' => 422,
'message' => '参数验证失败',
'errors' => $validator->getErrors()
], 422);
}
}
return $next($request);
}
private function getValidatorForRoute($routeName): ?string
{
$validators = [
'user.create' => UserCreateRequest::class,
'user.update' => UserUpdateRequest::class,
'order.create' => OrderCreateRequest::class,
];
return $validators[$routeName] ?? null;
}
}
创建专用请求类:
<?php
// requests/FormRequest.php
abstract class FormRequest
{
protected array $data;
protected array $errors = [];
protected bool $validated = false;
public function __construct(array $data)
{
$this->data = $data;
}
abstract public function rules(): array;
abstract public function messages(): array;
public function validate(): bool
{
$this->errors = [];
foreach ($this->rules() as $field => $rules) {
$value = $this->data[$field] ?? null;
$this->validateField($field, $value, $rules);
}
$this->validated = empty($this->errors);
return $this->validated;
}
protected function validateField($field, $value, $rules): void
{
// 使用上面创建的Validator类进行验证
$validator = new Validator();
foreach ($rules as $rule) {
// 验证逻辑...
}
}
public function validated(): array
{
if (!$this->validated) {
$this->validate();
}
return $this->validated ? array_intersect_key($this->data, $this->rules()) : [];
}
public function errors(): array
{
return $this->errors;
}
public function fails(): bool
{
return !$this->validate();
}
}
高级方案:使用Respect/Validation
使用成熟的验证库:Respect/Validation
<?php
use Respect\Validation\Validator as v;
class RequestValidator
{
public static function validate(array $data, array $rules): array
{
$errors = [];
foreach ($rules as $field => $validators) {
$value = $data[$field] ?? null;
foreach ($validators as $validator) {
try {
$validator->setName($field)->assert($value);
} catch (\Respect\Validation\Exceptions\ValidationException $e) {
$errors[$field][] = $e->getMessage();
}
}
}
return $errors;
}
}
// 使用示例
$rules = [
'username' => [
v::alnum()->noWhitespace()->length(3, 20),
v::notEmpty()
],
'email' => [
v::email()
],
'age' => [
v::intVal()->between(18, 100)
],
'password' => [
v::length(8, 32),
v::regex('/[A-Za-z]/'),
v::regex('/[0-9]/')
]
];
$errors = RequestValidator::validate($_POST, $rules);
if (!empty($errors)) {
// 处理错误
}
最终方案:使用Symfony Validator组件
对于大型项目,推荐使用Symfony Validator:
<?php
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\Constraints as Assert;
class UserRequest
{
#[Assert\NotBlank]
#[Assert\Length(min: 3, max: 20)]
public string $username;
#[Assert\NotBlank]
#[Assert\Email]
public string $email;
#[Assert\NotBlank]
#[Assert\Type('integer')]
#[Assert\Range(min: 18, max: 150)]
public int $age;
#[Assert\NotBlank]
#[Assert\Choice(['admin', 'user', 'guest'])]
public string $role;
}
// 验证
$validator = Validation::createValidatorBuilder()
->enableAttributeMapping()
->getValidator();
$request = new UserRequest();
$request->username = $_POST['username'] ?? '';
$request->email = $_POST['email'] ?? '';
$request->age = (int)($_POST['age'] ?? 0);
$request->role = $_POST['role'] ?? '';
$violations = $validator->validate($request);
if (count($violations) > 0) {
$errors = [];
foreach ($violations as $violation) {
$errors[$violation->getPropertyPath()][] = $violation->getMessage();
}
// 返回错误响应
response()->json(['errors' => $errors], 422);
}
完整架构示例
<?php
// 1. 创建验证器工厂
class ValidatorFactory
{
public static function make(string $type, array $data): FormRequest
{
$map = [
'user_create' => UserCreateRequest::class,
'user_update' => UserUpdateRequest::class,
'order_create' => OrderCreateRequest::class,
];
$class = $map[$type] ?? null;
if (!$class) {
throw new \InvalidArgumentException("Validator type '{$type}' not found");
}
return new $class($data);
}
}
// 2. 在控制器中使用
class UserController
{
public function store(Request $request)
{
// 统一的验证入口
$validator = ValidatorFactory::make('user_create', $request->all());
if ($validator->fails()) {
return response()->json([
'code' => 422,
'message' => 'Validation failed',
'errors' => $validator->errors()
], 422);
}
// 只获取验证通过的数据
$validatedData = $validator->validated();
// 业务逻辑...
$user = User::create($validatedData);
return response()->json([
'code' => 200,
'message' => '创建成功',
'data' => $user
]);
}
}
// 3. 全局注册验证中间件
// 在框架的全局中间件中注册
$app->addMiddleware(new ValidationMiddleware());
推荐方案
对于不同规模的项目,我的建议是:
- 小型项目:使用方案1,自己实现简单的验证器
- 中型项目:使用方案2,使用中间件+请求类
- 大型项目:使用方案4,集成Symfony Validator组件
最重要的是:
- 统一入口:所有参数验证都在同一个地方处理
- 统一返回格式:验证失败的响应格式保持一致
- 验证规则标准化:使用统一的验证规则定义方式
- 错误信息可配置:错误提示信息应该支持多语言和自定义
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播