本文目录导读:

在PHP中递归验证数组通常用于处理嵌套的多维数组数据,以下是几种常见的递归验证方案:
基础递归验证函数
<?php
function validateArrayRecursive(array $data, array $rules): array
{
$errors = [];
foreach ($rules as $key => $rule) {
// 检查键是否存在
if (!isset($data[$key])) {
if (isset($rule['required']) && $rule['required']) {
$errors[$key][] = "{$key}字段是必填的";
}
continue;
}
$value = $data[$key];
// 如果是嵌套规则(子数组验证)
if (isset($rule['type']) && $rule['type'] === 'array' && isset($rule['rules'])) {
if (is_array($value)) {
// 递归验证子数组
$childErrors = validateArrayRecursive($value, $rule['rules']);
if (!empty($childErrors)) {
$errors[$key] = $childErrors;
}
} else {
$errors[$key][] = "{$key}必须是数组";
}
} else {
// 常规验证规则
$fieldErrors = validateField($value, $rule, $key);
if (!empty($fieldErrors)) {
$errors[$key] = $fieldErrors;
}
}
}
return $errors;
}
function validateField($value, array $rules, string $fieldName): array
{
$errors = [];
// 类型验证
if (isset($rules['type'])) {
$typeValidators = [
'string' => 'is_string',
'int' => 'is_int',
'float' => 'is_float',
'numeric' => 'is_numeric',
'bool' => 'is_bool',
'email' => function($v) { return filter_var($v, FILTER_VALIDATE_EMAIL) !== false; }
];
if (isset($typeValidators[$rules['type']])) {
$validator = $typeValidators[$rules['type']];
if (!$validator($value)) {
$errors[] = "{$fieldName}必须是{$rules['type']}类型";
}
}
}
// 最小值验证
if (isset($rules['min'])) {
if (is_numeric($value) && $value < $rules['min']) {
$errors[] = "{$fieldName}不能小于{$rules['min']}";
}
if (is_string($value) && strlen($value) < $rules['min']) {
$errors[] = "{$fieldName}长度不能小于{$rules['min']}";
}
}
// 最大值验证
if (isset($rules['max'])) {
if (is_numeric($value) && $value > $rules['max']) {
$errors[] = "{$fieldName}不能大于{$rules['max']}";
}
if (is_string($value) && strlen($value) > $rules['max']) {
$errors[] = "{$fieldName}长度不能大于{$rules['max']}";
}
}
// 正则验证
if (isset($rules['pattern']) && is_string($value)) {
if (!preg_match($rules['pattern'], $value)) {
$errors[] = "{$fieldName}格式不正确";
}
}
// 枚举验证
if (isset($rules['in']) && !in_array($value, $rules['in'])) {
$errors[] = "{$fieldName}必须是以下值之一:" . implode(', ', $rules['in']);
}
return $errors;
}
使用示例
<?php
// 定义验证规则
$rules = [
'name' => [
'type' => 'string',
'required' => true,
'min' => 2,
'max' => 50
],
'age' => [
'type' => 'int',
'required' => true,
'min' => 0,
'max' => 150
],
'email' => [
'type' => 'email',
'required' => true
],
'address' => [
'type' => 'array',
'required' => true,
'rules' => [
'city' => [
'type' => 'string',
'required' => true,
'min' => 2
],
'zip' => [
'type' => 'string',
'pattern' => '/^\d{5}$/'
],
'country' => [
'type' => 'string',
'in' => ['中国', '美国', '日本']
]
]
],
'hobbies' => [
'type' => 'array',
'rules' => [
'*' => [ // * 表示验证数组中的每个元素
'type' => 'string',
'min' => 2,
'max' => 20
]
]
]
];
// 测试数据
$testData = [
'name' => '张三',
'age' => 25,
'email' => 'zhangsan@example.com',
'address' => [
'city' => '北京',
'zip' => '100000',
'country' => '中国'
],
'hobbies' => ['读书', '游泳', '旅游']
];
// 执行验证
$errors = validateArrayRecursive($testData, $rules);
if (empty($errors)) {
echo "验证通过!\n";
} else {
echo "验证失败:\n";
print_r($errors);
}
高级递归验证(支持数组元素验证)
<?php
function validateNestedArray(array $data, array $rules): array
{
$errors = [];
foreach ($rules as $key => $rule) {
$value = $data[$key] ?? null;
// 处理通配符规则(数组每个元素验证)
if ($key === '*') {
if (is_array($value)) {
foreach ($value as $index => $item) {
$itemErrors = validateField($item, $rule, "元素[{$index}]");
if (!empty($itemErrors)) {
$errors[$index] = $itemErrors;
}
}
}
continue;
}
// 处理可选字段
if ($value === null) {
if (isset($rule['required']) && $rule['required']) {
$errors[$key][] = "{$key}是必填的";
}
continue;
}
// 递归处理子数组
if (isset($rule['type']) && $rule['type'] === 'array' && is_array($value)) {
if (isset($rule['rules'])) {
$childErrors = validateNestedArray($value, $rule['rules']);
if (!empty($childErrors)) {
$errors[$key] = $childErrors;
}
}
} else {
$fieldErrors = validateField($value, $rule, $key);
if (!empty($fieldErrors)) {
$errors[$key] = $fieldErrors;
}
}
}
return $errors;
}
使用类封装
<?php
class ArrayValidator
{
private array $errors = [];
public function validate(array $data, array $rules): bool
{
$this->errors = [];
$this->validateRecursive($data, $rules);
return empty($this->errors);
}
public function getErrors(): array
{
return $this->errors;
}
private function validateRecursive(array $data, array $rules, string $path = ''): void
{
foreach ($rules as $key => $rule) {
$currentPath = $path ? "{$path}.{$key}" : $key;
$value = $data[$key] ?? null;
if ($value === null) {
if (($rule['required'] ?? false)) {
$this->addError($currentPath, "{$currentPath}是必填的");
}
continue;
}
// 递归验证子数组
if (isset($rule['type']) && $rule['type'] === 'array' && isset($rule['rules'])) {
if (!is_array($value)) {
$this->addError($currentPath, "{$currentPath}必须是数组");
} else {
$this->validateRecursive($value, $rule['rules'], $currentPath);
}
} else {
$this->validateField($value, $rule, $currentPath);
}
}
}
private function validateField($value, array $rule, string $path): void
{
// 类型验证
if (isset($rule['type'])) {
$typeCheck = [
'string' => is_string($value),
'int' => is_int($value),
'float' => is_float($value),
'numeric' => is_numeric($value),
'bool' => is_bool($value),
'array' => is_array($value),
'email' => filter_var($value, FILTER_VALIDATE_EMAIL) !== false
];
if (isset($typeCheck[$rule['type']]) && !$typeCheck[$rule['type']]) {
$this->addError($path, "{$path}必须是{$rule['type']}类型");
}
}
// 其他验证规则...
if (isset($rule['min'])) {
if (is_string($value) && mb_strlen($value) < $rule['min']) {
$this->addError($path, "{$path}长度不能小于{$rule['min']}");
}
if (is_numeric($value) && $value < $rule['min']) {
$this->addError($path, "{$path}不能小于{$rule['min']}");
}
}
if (isset($rule['max'])) {
if (is_string($value) && mb_strlen($value) > $rule['max']) {
$this->addError($path, "{$path}长度不能大于{$rule['max']}");
}
if (is_numeric($value) && $value > $rule['max']) {
$this->addError($path, "{$path}不能大于{$rule['max']}");
}
}
if (isset($rule['pattern']) && is_string($value)) {
if (!preg_match($rule['pattern'], $value)) {
$this->addError($path, "{$path}格式不正确");
}
}
}
private function addError(string $path, string $message): void
{
if (!isset($this->errors[$path])) {
$this->errors[$path] = [];
}
$this->errors[$path][] = $message;
}
}
// 使用示例
$validator = new ArrayValidator();
$isValid = $validator->validate($testData, $rules);
if (!$isValid) {
print_r($validator->getErrors());
}
关键点说明
- 递归结构:验证规则可以嵌套定义,函数会递归处理子数组
- 路径追踪:记录验证路径,帮助定位错误位置
- 灵活规则:支持类型、长度、范围、正则、枚举等多种验证
- 错误收集:收集所有错误而不是立即返回
- 可选字段:支持required属性控制字段是否为必填
根据实际需求,你可以扩展验证规则(如自定义验证函数、回调验证等)或使用现有的第三方验证库。