本文目录导读:

- 基础手动校验(简单场景)
- 使用Validation类库(推荐)
- 使用Symfony Validator(企业级)
- 通用校验基类(自定义封装)
- 针对RESTful API的完整示例
- 使用PHP 8 Attributes(现代PHP)
- 最佳实践建议
在PHP中做接口参数校验,我推荐以下几种方案:
基础手动校验(简单场景)
<?php
class UserController {
public function createUser() {
// 获取参数
$data = json_decode(file_get_contents('php://input'), true);
// 基础校验
$errors = [];
if (empty($data['username'])) {
$errors[] = '用户名不能为空';
} elseif (mb_strlen($data['username']) < 3 || mb_strlen($data['username']) > 20) {
$errors[] = '用户名长度必须在3-20个字符之间';
}
if (empty($data['email'])) {
$errors[] = '邮箱不能为空';
} elseif (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
$errors[] = '邮箱格式不正确';
}
if (!empty($errors)) {
http_response_code(400);
echo json_encode(['errors' => $errors]);
return;
}
// 处理业务逻辑...
}
}
使用Validation类库(推荐)
安装PHP Validation库
composer require respect/validation
使用示例
<?php
use Respect\Validation\Validator as v;
class ApiValidator {
public static function validateCreateUser($data) {
$validator = v::key('username', v::stringType()->length(3, 20))
->key('email', v::email())
->key('age', v::intType()->between(18, 100))
->key('gender', v::stringType()->in(['male', 'female']), false);
try {
$validator->assert($data);
return ['valid' => true];
} catch (\Respect\Validation\Exceptions\ValidationException $e) {
return [
'valid' => false,
'errors' => $e->getMessages()
];
}
}
}
使用Symfony Validator(企业级)
<?php
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\Constraints as Assert;
class CreateUserRequest {
/**
* @Assert\NotBlank()
* @Assert\Length(min=3, max=20)
*/
public $username;
/**
* @Assert\NotBlank()
* @Assert\Email()
*/
public $email;
/**
* @Assert\Type(type="integer")
* @Assert\Range(min=18, max=100)
*/
public $age;
}
// 使用
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator();
$request = new CreateUserRequest();
$request->username = $_POST['username'] ?? '';
$request->email = $_POST['email'] ?? '';
$request->age = $_POST['age'] ?? '';
$errors = $validator->validate($request);
if (count($errors) > 0) {
foreach ($errors as $error) {
echo $error->getPropertyPath() . ': ' . $error->getMessage() . "\n";
}
}
通用校验基类(自定义封装)
<?php
abstract class BaseApiController {
protected function validate(array $rules, array $data) {
$errors = [];
foreach ($rules as $field => $validations) {
$value = $data[$field] ?? null;
foreach ($validations as $rule => $params) {
$method = 'validate' . ucfirst($rule);
if (method_exists($this, $method)) {
$result = $this->$method($value, $params);
if ($result !== true) {
$errors[$field][] = $result;
}
}
}
}
if (!empty($errors)) {
$this->response(['errors' => $errors], 400);
}
return true;
}
protected function validateRequired($value) {
return !empty($value) ? true : '该字段为必填项';
}
protected function validateEmail($value) {
return filter_var($value, FILTER_VALIDATE_EMAIL) !== false
? true : '邮箱格式不正确';
}
protected function validateMinLength($value, $min) {
return strlen($value) >= $min ? true : "长度不能小于{$min}";
}
// 更多校验方法...
protected function response($data, $status = 200) {
http_response_code($status);
echo json_encode($data);
exit;
}
}
// 使用
class OrderController extends BaseApiController {
public function createOrder() {
$params = [
'user_id' => 123,
'amount' => 100.50,
'email' => 'test@example.com'
];
$rules = [
'user_id' => ['required', 'integer'],
'amount' => ['required', 'numeric', 'min:0.01'],
'email' => ['email']
];
$this->validate($rules, $params);
// 业务逻辑...
}
}
针对RESTful API的完整示例
<?php
header('Content-Type: application/json; charset=utf-8');
class ApiValidator {
private $data;
private $errors = [];
public function __construct(array $data) {
$this->data = $data;
}
public function check($field, $rules) {
if (!isset($this->data[$field])) {
if (in_array('required', $rules)) {
$this->errors[$field][] = '字段缺失';
}
return $this;
}
$value = $this->data[$field];
foreach ($rules as $rule) {
// 解析带参数的规则,如: min:3
$parts = explode(':', $rule);
$ruleName = $parts[0];
$params = $parts[1] ?? null;
switch ($ruleName) {
case 'required':
if (empty($value)) {
$this->errors[$field][] = '该字段不能为空';
}
break;
case 'email':
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
$this->errors[$field][] = '邮箱格式不正确';
}
break;
case 'numeric':
if (!is_numeric($value)) {
$this->errors[$field][] = '必须为数字';
}
break;
case 'int':
if (!filter_var($value, FILTER_VALIDATE_INT)) {
$this->errors[$field][] = '必须为整数';
}
break;
case 'min':
if ($value < $params) {
$this->errors[$field][] = "不能小于{$params}";
}
break;
case 'max':
if ($value > $params) {
$this->errors[$field][] = "不能大于{$params}";
}
break;
case 'string':
if (!is_string($value)) {
$this->errors[$field][] = '必须为字符串';
}
break;
}
}
return $this;
}
public function validate() {
if (!empty($this->errors)) {
http_response_code(422);
echo json_encode([
'success' => false,
'message' => '参数校验失败',
'errors' => $this->errors
]);
exit;
}
return true;
}
}
// 使用
$data = json_decode(file_get_contents('php://input'), true) ?? $_POST;
$validator = new ApiValidator($data);
$validator
->check('username', ['required', 'string', 'min:3', 'max:20'])
->check('email', ['required', 'email'])
->check('age', ['numeric', 'min:18', 'max:100'])
->check('sex', ['string'])
->validate();
echo json_encode(['success' => true, 'data' => $data]);
使用PHP 8 Attributes(现代PHP)
<?php
#[Attribute]
class Validate {
public function __construct(
public string $rule,
public mixed $params = null
) {}
}
class UserRequest {
#[Validate('required')]
#[Validate('minLength', 3)]
public string $name;
#[Validate('required')]
#[Validate('email')]
public string $email;
#[Validate('numeric')]
#[Validate('between', [18, 100])]
public int $age;
}
// 反射验证
class RequestValidator {
public static function validate(object $request): array {
$reflection = new ReflectionClass($request);
$errors = [];
foreach ($reflection->getProperties() as $property) {
$attributes = $property->getAttributes(Validate::class);
$value = $property->getValue($request);
foreach ($attributes as $attribute) {
$validate = $attribute->newInstance();
// 执行对应的验证逻辑...
}
}
return $errors;
}
}
最佳实践建议
- 分层校验:不要把校验逻辑放在业务逻辑中
- 统一错误格式:返回一致的错误结构
- 使用正规库:成熟可靠的库比手写更安全
- 考虑性能:对于高频接口,简单校验可能更合适
- 安全考虑:永远不要信任客户端数据
选择哪个方案取决于你的项目需求、PHP版本和团队熟悉度,对于大多数中小型项目,建议使用方案2(Respect Validation)或方案5(自定义验证器),它们既灵活又易维护。