PHP数组验证怎么递归

wen PHP项目 2

本文目录导读:

PHP数组验证怎么递归

  1. 基础递归验证函数
  2. 使用示例
  3. 高级递归验证(支持数组元素验证)
  4. 使用类封装
  5. 关键点说明

在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());
}

关键点说明

  1. 递归结构:验证规则可以嵌套定义,函数会递归处理子数组
  2. 路径追踪:记录验证路径,帮助定位错误位置
  3. 灵活规则:支持类型、长度、范围、正则、枚举等多种验证
  4. 错误收集:收集所有错误而不是立即返回
  5. 可选字段:支持required属性控制字段是否为必填

根据实际需求,你可以扩展验证规则(如自定义验证函数、回调验证等)或使用现有的第三方验证库。

抱歉,评论功能暂时关闭!