使用PHP处理验证错误的最简洁方法是什么?

Log*_*man 8 php validation error-handling

只要我一直在开发Web应用程序,我一直在寻找更好的方法来处理验证.通常需要捕获多个验证错误,因此我想知道是否有比下面更好的方法.

现在我assert在自己开发的框架中有一个方法.方法的一个例子是:

assert(($foo == 1), 'Foo is not equal to 1');

如果第一个参数中的条件为false,则将第二个参数中的错误消息添加到$errors数组中(该数组包含在$eh提供便利函数的类中(由下面引用)hasErrors()).

这种方法有效,但在实践中很麻烦.考虑以下代码:

public function submit($foo, $bar, $baz)
{
    assert(($foo == 1), 'Foo is not equal to 1');
    assert(($bar == 2), 'Bar is not equal to 2');

    if (!$eh->hasErrors())
    {
        assert(($baz == 3), 'Baz is not equal to 3');

        if (!$eh->hasErrors())
        {
            finallyDoSomething();
            return;
        }
    }

    outputErrors();
}
Run Code Online (Sandbox Code Playgroud)

这是相当普遍的事情.我想在继续之前检查两个条件,然后如果这些条件通过,请在最终做我想做的事之前检查第三个条件.如您所见,此代码中的大多数行都与验证有关.在实际的应用程序中,将有更多的验证和可能更多嵌套的if语句.

有没有人有比这更好的处理验证结构?如果有更优雅地处理这个问题的框架,那么它们是什么以及它们如何实现呢?多个嵌套的if语句似乎是解决问题的"强力"解决方案.

只是一个注释,我理解在一个类中包含一些常见的验证函数可能是个好主意,这样我就可以通过调用这些函数来检查长度,字符串格式等.我要问的是一种更清晰的代码结构方法,而不是我实际检查错误的方法.

谢谢!

alg*_*net 6

请检查Respect\Validation.这是一个为那个purpouse而建的图书馆.它可以非常轻松地处理多个规则并使用异常来处理错误.这是一个快速示例:

<?php

use Respect\Validation\Validator as v;

$usernameValidator = v::alnum()->noWhitespace()->length(1,15);

$valid = $usernameValidator->validate("alganet"); //$valid now == true
$valid = $usernameValidator->validate("ácido acético"); //$valid now == false
Run Code Online (Sandbox Code Playgroud)

现在使用例外:

try {
    $usernameValidator->assert("foo # bar");
} catch (Exception $e) {
    $errors = $e->findMessages('alnum', 'noWhitespace', 'length');
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,$errors变量将是这样的:

array(
    "alnum" => '"foo # bar" must contain only letters and digits',
    "noWhitespace" => '"foo # bar" must not contain whitespace',
    "length" => null
)
Run Code Online (Sandbox Code Playgroud)

我使用"foo #bar"打破了两个先前声明的规则:它有空格,并且它有一个非alnum char.对于每个未通过的规则,将返回一条消息.由于"长度"正常,因此错误消息为空.

文档包括几个样本,包括嵌套的分层规则和更好的异常处理.还有30多个内置验证器的广泛样本列表.

希望有所帮助!

  • +1.我昨天在一个快速项目中终于尝试了"Respect\Validation".非常有用的库! (2认同)

Dar*_*ght 5

抛出异常怎么样?您可以使用 try /catch 块显式捕获异常,和/或使用以下方法捕获它们set_exception_handler()

PHP 中定义了许多有用的异常类型,如果您需要异常处理的粒度,可以使用它们来发挥自己的优势。另外您还可以定义自定义异常。

http://php.net/manual/en/function.set-exception-handler.php http://www.php.net/manual/en/spl.exceptions.php

编辑

要回答有关其他一些框架如何解决此问题的问题 - 明智地使用异常似乎很常见。使用它们的有用之处在于,假设您有一个特定的方法,它执行了许多可能是错误的不同验证 - 您可以在每种情况下抛出适当的异常,但您不必处理不同的可能异常那个方法。相反,根据您构建代码的方式,您可以允许异常冒泡到代码中更集中的位置,您可以在其中捕获它并进行适当的处​​理。

编辑2

详细说明我最后的评论filter_input_array()

基于一个非常简单的示例,其中包含已发布的用户数据。首先创建一个定义:

$userFormDefinition = array(
    'email' => FILTER_VALIDATE_EMAIL,
    'age'   => FILTER_VALIDATE_INT,
    'name'  => array(
        'filter'  => FILTER_VALIDATE_REGEXP, 
        'options' => array('regexp' => '/^\w+$/')
    ),
);
Run Code Online (Sandbox Code Playgroud)

然后使用通用验证类(类定义如下):

$formValidator = new FormValidator();
$formValidator->validatePost($userFormDefinition);

if ($formValidator->isValid()) {

    // if valid, retrieve the array
    // and use the values how you wish

    $values = $formValidator->getValues();

    // for example, extract and populate
    // a User object, or whatever :)

    extract($values);

    $user = new User();
    $user->setName($name);
    $user->setEmail($email);
    $user->setAge($age);

    // etc.
}
Run Code Online (Sandbox Code Playgroud)

FormValidator 的一个非常基本(且未经测试)的实现。

基本用例是调用适当的方法来过滤请求方法。这反过来会检查返回的值并决定输入是否有效。

这可能需要大量的爱 -尤其是方法filterInput,因为您可能需要进行一些测试以确保正确处理“真实”或“虚假”值。我正在考虑复选框类型值。直接in_array检查false可能不会像这里实现的那样削减它。但是您可以通过定义传递大量标志。

我想您还可以通过比较结果数组和定义的计数来检查丢失的输入$values,以确保它们匹配。定义中未包含的其他输入将被过滤掉(您可能想检查这一点,但我相当确定这一点)。

<?php

class FormValidator
{   
    private $isValid = false;

    private $isBound = false;

    private $values  = array();

    public function validatePost(array $definition)
    {
        // additional REQUEST_METHOD checking here?
        $this->filter(INPUT_POST, $definition);
    }

    public function validateGet(array $definition)
    {
        // additional REQUEST_METHOD checking here?
        $this->filterInput(INPUT_GET, $definition);
    }

    protected function filterInput($type, $definition)
    {
        $this->isBound = true;

        $this->values = filter_input_array($type, $definition);

        // might have to do some reading on nulls vs false, 
        // and validating checkbox type values here... you can
        // set all sorts of flags so a better implementation
        // would probably be required here... :s

        if (is_array($this->values) && !in_array(false, $this->values))) {
            $this->isValid = true;
        }   
    }

    public function isValid()
    {
        if (!$this->isBound) {
            throw new Exception("you didn't validate yet!");
        }

        return $this->isValid;
    }

    public function getValues()
    {
        if (!$this->isBound) {
            throw new Exception("You didn't validate yet!");
        }

        return $this->values;
    }
}
Run Code Online (Sandbox Code Playgroud)

无论如何,我会说重构并测试该类中的 bejayzis(甚至完全更改它),但希望它概述了基本思想:对于每种类型的输入,创建一个定义,然后使用通用验证类来过滤并确保有效性。

希望这可以帮助。filter_inputfilter_input_array摇滚:)