PHP 怎么PHP回调校验

wen PHP项目 1

本文目录导读:

PHP 怎么PHP回调校验

  1. 函数回调校验
  2. 回调参数校验
  3. 数组回调的高级校验
  4. 类型校验的回调
  5. 异步回调校验(Promise 模式)
  6. 最佳实践建议
  7. 实际应用示例

在 PHP 中实现回调校验(Callback Validation)通常有以下几种常见场景和方法:

函数回调校验

检查回调是否有效

<?php
// 检查是否是有效的回调
function validateCallback($callback) {
    if (!is_callable($callback)) {
        throw new InvalidArgumentException('Invalid callback provided');
    }
    return true;
}
// 使用示例
$callbacks = [
    'myFunction',           // 函数名字符串
    ['MyClass', 'method'],  // 类方法数组
    [$object, 'method'],    // 对象方法数组
    function ($data) {      // 匿名函数
        return $data;
    },
    'MyClass::staticMethod' // 静态方法字符串
];
foreach ($callbacks as $callback) {
    try {
        validateCallback($callback);
        echo "Valid callback\n";
    } catch (Exception $e) {
        echo "Invalid callback: " . $e->getMessage() . "\n";
    }
}

回调参数校验

<?php
class CallbackValidator {
    /**
     * 校验回调函数返回的数据
     */
    public static function validateResult($callback, $data) {
        if (!is_callable($callback)) {
            throw new InvalidArgumentException('Callback is not callable');
        }
        $result = call_user_func($callback, $data);
        // 验证返回结果
        if ($result === false) {
            throw new RuntimeException('Callback returned false');
        }
        return $result;
    }
    /**
     * 带参数数量的回调校验
     */
    public static function validateWithArgs($callback, $expectedArgs = 0) {
        if (!is_callable($callback)) {
            throw new InvalidArgumentException('Callback is not callable');
        }
        // 获取回调的参数数量(仅对函数有效)
        if (is_string($callback) && function_exists($callback)) {
            $reflection = new ReflectionFunction($callback);
            $actualArgs = $reflection->getNumberOfParameters();
            if ($actualArgs < $expectedArgs) {
                throw new InvalidArgumentException(
                    "Callback expects {$actualArgs} arguments, but {$expectedArgs} required"
                );
            }
        }
        return true;
    }
}

数组回调的高级校验

<?php
function validateArrayCallback($array, $callback) {
    if (!is_callable($callback)) {
        return false;
    }
    $results = array_map($callback, $array);
    // 检查全部通过
    foreach ($results as $key => $result) {
        if (!$result) {
            return [
                'valid' => false,
                'failed_key' => $key,
                'message' => "Validation failed for key: {$key}"
            ];
        }
    }
    return ['valid' => true];
}
// 使用示例
$data = [
    'email' => 'user@example.com',
    'age' => 25,
    'name' => 'John Doe'
];
$validationRules = [
    'email' => function ($value) {
        return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
    },
    'age' => function ($value) {
        return is_numeric($value) && $value >= 18;
    },
    'name' => function ($value) {
        return is_string($value) && strlen($value) > 2;
    }
];
foreach ($data as $key => $value) {
    $result = validateArrayCallback([$value], $validationRules[$key]);
    echo "Field '{$key}': " . ($result['valid'] ? 'Passed' : 'Failed') . "\n";
}

类型校验的回调

<?php
class TypeValidator {
    /**
     * 创建类型校验回调
     */
    public static function makeTypeValidator($type) {
        return function ($value) use ($type) {
            switch ($type) {
                case 'string':
                    return is_string($value);
                case 'integer':
                case 'int':
                    return is_int($value);
                case 'float':
                case 'double':
                    return is_float($value) || is_double($value);
                case 'array':
                    return is_array($value);
                case 'boolean':
                case 'bool':
                    return is_bool($value);
                case 'null':
                    return is_null($value);
                case 'numeric':
                    return is_numeric($value);
                default:
                    return false;
            }
        };
    }
    /**
     * 校验多个字段
     */
    public static function validateFields($data, $rules) {
        $errors = [];
        foreach ($rules as $field => $validator) {
            if (!isset($data[$field])) {
                $errors[$field] = "Field '{$field}' is missing";
                continue;
            }
            if (is_callable($validator) && !$validator($data[$field])) {
                $errors[$field] = "Field '{$field}' failed validation";
            }
        }
        return empty($errors) ? true : $errors;
    }
}
// 使用示例
$data = [
    'username' => 'john_doe',
    'email' => 'invalid-email',
    'age' => 'twenty-five',
    'active' => true
];
$rules = [
    'username' => TypeValidator::makeTypeValidator('string'),
    'email' => function ($value) {
        return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
    },
    'age' => TypeValidator::makeTypeValidator('integer'),
    'active' => TypeValidator::makeTypeValidator('boolean')
];
$result = TypeValidator::validateFields($data, $rules);
if ($result === true) {
    echo "All validation passed!\n";
} else {
    echo "Validation errors:\n";
    foreach ($result as $field => $error) {
        echo "  - {$error}\n";
    }
}

异步回调校验(Promise 模式)

<?php
class AsyncCallbackValidator {
    public static function validateAsync($callback) {
        if (!is_callable($callback)) {
            return Promise::reject(new InvalidArgumentException('Invalid callback'));
        }
        return Promise::resolve()
            ->then(function () use ($callback) {
                $result = call_user_func($callback);
                if (!$result) {
                    throw new RuntimeException('Validation failed');
                }
                return $result;
            });
    }
}

最佳实践建议

<?php
/**
 * 完整的回调校验框架
 */
class SecureCallbackValidator {
    private $allowedNamespaces = ['App\\Validators\\'];
    /**
     * 安全的回调校验
     */
    public function validate($callback, $options = []) {
        // 1. 基本可调用性检查
        if (!is_callable($callback)) {
            throw new InvalidArgumentException('Callback is not callable');
        }
        // 2. 字符串回调安全检查(防止代码注入)
        if (is_string($callback)) {
            $this->checkStringCallback($callback);
        }
        // 3. 反射检查
        $reflection = $this->getReflection($callback);
        if (!$reflection->isUserDefined()) {
            throw new SecurityException('Cannot use internal PHP functions as callback');
        }
        // 4. 参数数量验证
        if (isset($options['expected_params'])) {
            $this->checkParameterCount($reflection, $options['expected_params']);
        }
        return true;
    }
    private function checkStringCallback($callback) {
        // 防止任意代码执行
        if (strpos($callback, '::') !== false || strpos($callback, '->') !== false) {
            throw new SecurityException('Unsafe callback string format');
        }
    }
    private function getReflection($callback) {
        if (is_array($callback)) {
            return new ReflectionMethod($callback[0], $callback[1]);
        }
        if (is_string($callback)) {
            return new ReflectionFunction($callback);
        }
        return new ReflectionFunction($callback);
    }
    private function checkParameterCount($reflection, $expected) {
        $actual = $reflection->getNumberOfParameters();
        if ($actual !== $expected) {
            throw new InvalidArgumentException(
                "Callback expects {$actual} parameters, {$expected} given"
            );
        }
    }
}

实际应用示例

<?php
// 表单验证框架
class FormValidator {
    private $rules;
    public function addRule($field, $validator) {
        $this->validateCallback($validator);
        $this->rules[$field][] = $validator;
        return $this;
    }
    public function validate($data) {
        $errors = [];
        foreach ($this->rules as $field => $validators) {
            foreach ($validators as $validator) {
                $result = call_user_func($validator, $data[$field] ?? null);
                if (is_string($result)) {
                    // 返回错误消息
                    $errors[$field] = $result;
                    break;
                } elseif ($result === false) {
                    $errors[$field] = "{$field} is invalid";
                    break;
                }
            }
        }
        return empty($errors) ? true : $errors;
    }
    private function validateCallback($callback) {
        if (!is_callable($callback)) {
            throw new InvalidArgumentException('Invalid callback');
        }
    }
}
// 使用
$validator = new FormValidator();
$validator
    ->addRule('username', function ($value) {
        return preg_match('/^[a-zA-Z0-9_]{3,20}$/', $value) ?: 'Invalid username format';
    })
    ->addRule('email', function ($value) {
        return filter_var($value, FILTER_VALIDATE_EMAIL) ? 'Invalid email' : true;
    });
$data = [
    'username' => 'john',
    'email' => 'invalid-email'
];
$result = $validator->validate($data);
if (is_array($result)) {
    print_r($result);
}

这些方法覆盖了 PHP 回调校验的主要场景,根据你的具体需求,可以选择合适的方法来实现回调校验,关键是要确保:

  1. 回调确实可调用
  2. 回调的参数和返回值符合预期
  3. 考虑安全性,防止恶意代码执行

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