对象应该在哪里验证?

时间:2014-10-22 11:36:41

标签: php validation

我的问题是,我不知道,对于输入验证的女性解决方案更好,如果有另一种更好的解决方案。那么,对象应该在哪里验证?一方面,对象应该始终是正确的。另一方面,如果用户指定了几个不正确的数据,那么它是一个更优雅的解决方案,可以通知他所有错误,而不仅仅是一个(第一次出现)。

// Solution 1:
try {
    $user = new User();
    $user->setFirstname($_POST['firstname']);
    $user->setSecondname($_POST['secondname']);
    $user->setLastname($_POST['lastname']);
    $user->hasLeftHand($_POST['has-left-hand']);
    $user->hasRightHand($_POST['has-right-hand']);
    $user->setHandedness($_POST['handedness']);
    $user->save($pdo);
} catch (Exception $e) {
    echo $e->getMessage();
}

// Solution 2:
$user = new User();
$user->setFirstname($_POST['firstname']);
$user->setSecondname($_POST['secondname']);
$user->setLastname($_POST['lastname']);
$user->hasLeftHand($_POST['has-left-hand']);
$user->hasRightHand($_POST['has-right-hand']);
$user->setHandedness($_POST['handedness']);

$errors = $user->validate();
if (empty($errors)) {
    $user->save($pdo);
} else {
    echo 'Some errors occured: ' . implode(', ', $errors);
}

// Solution 3:
try {
    $user = new User();
    $user->setFirstname($_POST['firstname']);
    $user->setSecondname($_POST['secondname']);
    $user->setLastname($_POST['lastname']);
    $user->hasLeftHand($_POST['has-left-hand']);
    $user->hasRightHand($_POST['has-right-hand']);
    $user->setHandedness($_POST['handedness']);
    $user->save($pdo);
} catch (Exception $e) {
    $errors = $user->validate();
    echo 'Some errors occured: ' . implode(', ', $errors);
}

解决方案1 ​​中,每个 set 方法验证输入。因此,对象始终是正确的。 save 方法仅将对象保存在数据库中。另一方面,如果所有数据都不正确,则只显示第一个错误。

解决方案2 中,我们允许该对象在 set 调用之间无法正确,但对数据库只能保存有效对象。 set 方法不验证输入。 validate 方法将对象作为一个整体进行验证,并返回找到的所有错误的列表。 save 方法如下所示:

public function save(PDO $pdo)
{
    if(! empty($this->validate())) {
        throw new Exception('Invalid state');
    }

    // Store in database
}

在此解决方案中更容易验证对象。那么,如何在解决方案1 ​​中编写以下代码?

$user->hasLeftHand(true);
$user->hasRightHand(false);
$user->setHandedness('right');

或者这段代码:

$user->setHandedness('right');
$user->hasLeftHand(true);
$user->hasRightHand(false);

解决方案3 解决方案2 的副本。 用户类的代码是相同的。仅更改其使用 - try-catch块。在我看来,这段代码看起来更清楚。

1 个答案:

答案 0 :(得分:1)

输入验证应与验证域对象本身的正确性分开。许多框架都使用Form类。也许看看它是如何完成的:

简而言之,表单将验证输入,并在数据有效时填充绑定对象。

免责声明:这个问题是以意见为基础的,没有一个正确的答案......但我会回顾一下我们在评论中所讨论的内容以及我认为大多数人如何解决它。

从模型中单独输入验证

<?php

// class for input validation
class UserValidator
{
    public function validate(array $data)
    {
        $errors = array();
        if (isset($data['email'])) {
            if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
                $errors['email'] = 'email not valid';
            }
        } else {
            $errors['email'] = 'email is required';
        }
    }
}

// model class itself, does not implement extensive validation
class User
{
    protected $email;

    public function setEmail($email)
    {
        // only make sure we have a valid string, dont validate email again
        if (!is_string($email) || !strlen($email)) throw new \InvalidArgumentException('invalid email given');

        $this->email = $email;
        return $this;
    }
}

因此,此示例将输入验证分开,以便在处理表单数据时轻松提供用户反馈。模型本身只执行基本检查,并假设开发人员足够聪明,可以设置合理的数据......

<?php

// where you process a form POST...
$validator = new UserValidator();
$errors = $validator->validate($_POST);
if (count($errors)) {
    // provide feedback to your user, he gave us bogus data...
    return $errors;
}

// if we are here, we passed validation and can assume our data is good
$user = new User();
$user->setEmail($_POST['email']);

这是一个非常简化示例,您应该再次查看主要框架如何解决这个问题,他们已经有很多人在考虑这个问题了...... 正如Zend和Symfony之间的差异所强调的那样:对此没有金锤。