PHP 验证器工厂模式

wen PHP项目 2

本文目录导读:

PHP 验证器工厂模式

  1. 验证器接口
  2. 具体验证器实现
  3. 验证器工厂
  4. 验证器管理器(集成多个验证器)
  5. 使用示例
  6. 高级特性
  7. 测试类
  8. Composer 配置
  9. 核心优势

我来为您设计一个PHP验证器工厂模式的完整实现,包含示例和说明。

验证器接口

<?php
// ValidatorInterface.php
namespace App\Validators;
interface ValidatorInterface
{
    /**
     * 执行验证逻辑
     * @param mixed $value 待验证的值
     * @param array $options 验证选项
     * @return bool 验证是否通过
     */
    public function validate($value, array $options = []): bool;
    /**
     * 获取验证失败的错误消息
     * @return string
     */
    public function getMessage(): string;
    /**
     * 设置错误消息
     * @param string $message
     * @return self
     */
    public function setMessage(string $message): self;
}

具体验证器实现

<?php
// RequiredValidator.php
namespace App\Validators;
class RequiredValidator implements ValidatorInterface
{
    private $message = '该字段是必填的';
    public function validate($value, array $options = []): bool
    {
        if (isset($options['message'])) {
            $this->setMessage($options['message']);
        }
        if ($value === null || $value === '') {
            return false;
        }
        if (is_array($value) && empty($value)) {
            return false;
        }
        return true;
    }
    public function getMessage(): string
    {
        return $this->message;
    }
    public function setMessage(string $message): self
    {
        $this->message = $message;
        return $this;
    }
}
<?php
// EmailValidator.php
namespace App\Validators;
class EmailValidator implements ValidatorInterface
{
    private $message = '邮箱格式不正确';
    public function validate($value, array $options = []): bool
    {
        if (isset($options['message'])) {
            $this->setMessage($options['message']);
        }
        if (empty($value)) {
            return true; // 可选字段,如果必填则使用 RequiredValidator
        }
        return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
    }
    public function getMessage(): string
    {
        return $this->message;
    }
    public function setMessage(string $message): self
    {
        $this->message = $message;
        return $this;
    }
}
<?php
// LengthValidator.php
namespace App\Validators;
class LengthValidator implements ValidatorInterface
{
    private $message = '长度不符合要求';
    public function validate($value, array $options = []): bool
    {
        $min = $options['min'] ?? 0;
        $max = $options['max'] ?? PHP_INT_MAX;
        if (isset($options['message'])) {
            $this->setMessage($options['message']);
        }
        $length = mb_strlen($value, 'UTF-8');
        if ($length < $min) {
            $this->setMessage("长度不能小于 {$min} 个字符");
            return false;
        }
        if ($length > $max) {
            $this->setMessage("长度不能大于 {$max} 个字符");
            return false;
        }
        return true;
    }
    public function getMessage(): string
    {
        return $this->message;
    }
    public function setMessage(string $message): self
    {
        $this->message = $message;
        return $this;
    }
}
<?php
// NumericValidator.php
namespace App\Validators;
class NumericValidator implements ValidatorInterface
{
    private $message = '必须是数字';
    public function validate($value, array $options = []): bool
    {
        if (isset($options['message'])) {
            $this->setMessage($options['message']);
        }
        if (!is_numeric($value)) {
            return false;
        }
        // 检查范围
        if (isset($options['min']) && $value < $options['min']) {
            $this->setMessage("数字不能小于 {$options['min']}");
            return false;
        }
        if (isset($options['max']) && $value > $options['max']) {
            $this->setMessage("数字不能大于 {$options['max']}");
            return false;
        }
        return true;
    }
    public function getMessage(): string
    {
        return $this->message;
    }
    public function setMessage(string $message): self
    {
        $this->message = $message;
        return $this;
    }
}
<?php
// RegexValidator.php
namespace App\Validators;
class RegexValidator implements ValidatorInterface
{
    private $message = '格式不正确';
    public function validate($value, array $options = []): bool
    {
        if (!isset($options['pattern'])) {
            throw new \InvalidArgumentException('正则表达式验证器需要提供pattern选项');
        }
        if (isset($options['message'])) {
            $this->setMessage($options['message']);
        }
        return preg_match($options['pattern'], $value) === 1;
    }
    public function getMessage(): string
    {
        return $this->message;
    }
    public function setMessage(string $message): self
    {
        $this->message = $message;
        return $this;
    }
}

验证器工厂

<?php
// ValidatorFactory.php
namespace App\Validators;
use InvalidArgumentException;
class ValidatorFactory
{
    /**
     * @var array 验证器别名映射
     */
    private static $aliases = [
        'required' => RequiredValidator::class,
        'email'    => EmailValidator::class,
        'length'   => LengthValidator::class,
        'numeric'  => NumericValidator::class,
        'integer'  => NumericValidator::class,
        'regex'    => RegexValidator::class,
    ];
    /**
     * @var array 已创建的验证器实例缓存
     */
    private static $instances = [];
    /**
     * 创建验证器实例
     * @param string $type 验证器类型
     * @param array $options 验证器选项
     * @return ValidatorInterface
     * @throws InvalidArgumentException
     */
    public static function create(string $type, array $options = []): ValidatorInterface
    {
        $class = self::resolveClass($type);
        // 使用选项作为缓存键的一部分
        $cacheKey = $type . ':' . md5(json_encode($options));
        if (!isset(self::$instances[$cacheKey])) {
            self::$instances[$cacheKey] = new $class();
        }
        return self::$instances[$cacheKey];
    }
    /**
     * 解析验证器类名
     * @param string $type
     * @return string
     * @throws InvalidArgumentException
     */
    private static function resolveClass(string $type): string
    {
        $type = strtolower($type);
        if (isset(self::$aliases[$type])) {
            return self::$aliases[$type];
        }
        // 尝试按类名解析(支持App\Validators\CustomValidator格式)
        $class = 'App\\Validators\\' . ucfirst($type) . 'Validator';
        if (class_exists($class)) {
            return $class;
        }
        throw new InvalidArgumentException("未知的验证器类型: {$type}");
    }
    /**
     * 注册自定义验证器
     * @param string $alias 别名
     * @param string $class 类名
     * @throws InvalidArgumentException
     */
    public static function register(string $alias, string $class): void
    {
        if (!class_exists($class) || !in_array(ValidatorInterface::class, class_implements($class))) {
            throw new InvalidArgumentException("{$class} 必须实现 ValidatorInterface");
        }
        self::$aliases[strtolower($alias)] = $class;
    }
    /**
     * 清理实例缓存
     */
    public static function clearCache(): void
    {
        self::$instances = [];
    }
}

验证器管理器(集成多个验证器)

<?php
// ValidationManager.php
namespace App\Validators;
class ValidationManager
{
    private $rules = [];
    private $data = [];
    private $errors = [];
    public function __construct(array $data = [])
    {
        $this->data = $data;
    }
    /**
     * 添加验证规则
     * @param string $field 字段名
     * @param string $validator 验证器类型
     * @param array $options 验证选项
     * @return self
     */
    public function addRule(string $field, string $validator, array $options = []): self
    {
        $this->rules[$field][] = [
            'validator' => $validator,
            'options' => $options
        ];
        return $this;
    }
    /**
     * 批量添加验证规则
     * @param array $rules 格式: ['字段名' => [['validator' => 'required'], ...]]
     * @return self
     */
    public function addRules(array $rules): self
    {
        foreach ($rules as $field => $fieldRules) {
            foreach ($fieldRules as $rule) {
                $validator = $rule['validator'] ?? null;
                if (!$validator) {
                    continue;
                }
                $options = $rule['options'] ?? [];
                $this->addRule($field, $validator, $options);
            }
        }
        return $this;
    }
    /**
     * 执行验证
     * @return bool
     */
    public function validate(): bool
    {
        $this->errors = [];
        foreach ($this->rules as $field => $rules) {
            $value = $this->data[$field] ?? null;
            foreach ($rules as $rule) {
                $validator = ValidatorFactory::create(
                    $rule['validator'],
                    $rule['options']
                );
                if (!$validator->validate($value, $rule['options'])) {
                    $this->errors[$field][] = $validator->getMessage();
                    break; // 一个字段只显示第一个错误
                }
            }
        }
        return empty($this->errors);
    }
    /**
     * 获取所有错误信息
     * @return array
     */
    public function getErrors(): array
    {
        return $this->errors;
    }
    /**
     * 获取指定字段的错误信息
     * @param string $field
     * @return array
     */
    public function getFieldErrors(string $field): array
    {
        return $this->errors[$field] ?? [];
    }
}

使用示例

<?php
// usage.php
require 'vendor/autoload.php';
use App\Validators\ValidatorFactory;
use App\Validators\ValidationManager;
use App\Validators\CustomValidators\PhoneValidator;
// 1. 基本用法
$emailValidator = ValidatorFactory::create('email');
$isValid = $emailValidator->validate('user@example.com');
echo $isValid ? "Email有效\n" : "Email无效\n";
// 2. 带选项的验证
$lengthValidator = ValidatorFactory::create('length', ['min' => 3, 'max' => 10]);
$isValid = $lengthValidator->validate('Hello');
echo $isValid ? "长度有效\n" : "长度无效\n";
// 3. 注册自定义验证器
ValidatorFactory::register('phone', PhoneValidator::class);
// 4. 使用验证管理器
$data = [
    'username' => 'JohnDoe',
    'email' => 'john@example.com',
    'age' => '25',
    'phone' => '13800138000'
];
$validationManager = new ValidationManager($data);
$validationManager
    ->addRule('username', 'required', ['message' => '用户名不能为空'])
    ->addRule('username', 'length', ['min' => 3, 'max' => 20, 'message' => '用户名长度需在3-20之间'])
    ->addRule('email', 'required', ['message' => '邮箱不能为空'])
    ->addRule('email', 'email', ['message' => '邮箱格式不正确'])
    ->addRule('age', 'numeric', ['min' => 18, 'max' => 100])
    ->addRule('phone', 'phone', ['message' => '手机号格式不正确']);
if ($validationManager->validate()) {
    echo "所有验证通过!\n";
} else {
    print_r($validationManager->getErrors());
}
// 5. 批量添加规则示例
$rules = [
    'name' => [
        ['validator' => 'required', 'options' => ['message' => '姓名必填']],
        ['validator' => 'length', 'options' => ['min' => 2, 'max' => 50, 'message' => '姓名长度需在2-50之间']]
    ],
    'age' => [
        ['validator' => 'numeric', 'options' => ['min' => 1, 'max' => 150, 'message' => '年龄需在1-150之间']]
    ]
];
$manager = new ValidationManager([
    'name' => 'John',
    'age' => 30
]);
$manager->addRules($rules);
if ($manager->validate()) {
    echo "批量规则验证通过!\n";
} else {
    print_r($manager->getErrors());
}
// 6. 自定义验证器类
// CustomValidators/PhoneValidator.php
namespace App\Validators\CustomValidators;
use App\Validators\ValidatorInterface;
class PhoneValidator implements ValidatorInterface
{
    private $message = '手机号格式不正确';
    public function validate($value, array $options = []): bool
    {
        if (isset($options['message'])) {
            $this->setMessage($options['message']);
        }
        if (empty($value)) {
            return true;
        }
        // 中国大陆手机号简单验证
        return preg_match('/^1[3-9]\d{9}$/', $value) === 1;
    }
    public function getMessage(): string
    {
        return $this->message;
    }
    public function setMessage(string $message): self
    {
        $this->message = $message;
        return $this;
    }
}

高级特性

<?php
// AdvancedValidatorFactory.php - 支持闭包验证器
namespace App\Validators;
class AdvancedValidatorFactory
{
    private static $closures = [];
    /**
     * 注册闭包验证器
     * @param string $name
     * @param callable $callback 接收值和选项,返回bool
     */
    public static function registerClosure(string $name, callable $callback): void
    {
        self::$closures[$name] = $callback;
    }
    /**
     * 创建闭包验证器
     */
    public static function createClosure(string $name, callable $callback): ValidatorInterface
    {
        return new class($name, $callback) implements ValidatorInterface {
            private $name;
            private $callback;
            private $message;
            public function __construct(string $name, callable $callback)
            {
                $this->name = $name;
                $this->callback = $callback;
            }
            public function validate($value, array $options = []): bool
            {
                $this->message = $options['message'] ?? "验证失败";
                return call_user_func($this->callback, $value, $options);
            }
            public function getMessage(): string
            {
                return $this->message;
            }
            public function setMessage(string $message): self
            {
                $this->message = $message;
                return $this;
            }
        };
    }
}
// 使用闭包验证器
AdvancedValidatorFactory::registerClosure('even', function($value) {
    return $value % 2 === 0;
});
$validator = AdvancedValidatorFactory::createClosure('even', 
    AdvancedValidatorFactory::$closures['even']
);

测试类

<?php
// tests/ValidatorTest.php
use PHPUnit\Framework\TestCase;
use App\Validators\ValidatorFactory;
use App\Validators\ValidationManager;
class ValidatorTest extends TestCase
{
    public function testEmailValidation()
    {
        $validator = ValidatorFactory::create('email');
        $this->assertTrue($validator->validate('test@example.com'));
        $this->assertFalse($validator->validate('invalid-email'));
    }
    public function testRequiredValidation()
    {
        $validator = ValidatorFactory::create('required');
        $this->assertFalse($validator->validate(''));
        $this->assertFalse($validator->validate(null));
        $this->assertTrue($validator->validate('some value'));
    }
    public function testValidationManager()
    {
        $data = [
            'name' => 'John',
            'email' => 'john@example.com'
        ];
        $manager = new ValidationManager($data);
        $manager
            ->addRule('name', 'required')
            ->addRule('name', 'length', ['min' => 2])
            ->addRule('email', 'email');
        $this->assertTrue($manager->validate());
        $this->assertEmpty($manager->getErrors());
    }
}

Composer 配置

{
    "name": "validator-factory",
    "description": "PHP Validator Factory Pattern",
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "require": {
        "php": ">=7.4"
    }
}

核心优势

  1. 灵活扩展:新增验证器只需实现接口并注册
  2. 代码复用:验证器可重用,避免重复代码
  3. 配置集中:验证规则配置清晰,易于维护
  4. 错误处理:统一的错误消息管理
  5. 性能优化:实例缓存机制
  6. 开闭原则:对扩展开放,对修改关闭

这个验证器工厂模式适合各种PHP项目,从简单表单验证到复杂的数据校验场景都能很好的支持。

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