如何在验证表单中捕获多个异常

How do I catch multiple Exceptions in a validation form

我有一个用于注册用户的验证表单,我正在尝试尝试捕捉这个概念来验证我的模型中的输入数据。让我先向您展示我的代码:

模型注册

public function register (string $username, string $email, string $email_repeat, string $password, string $password_repeat, string $ip, string $reCaptcha) {
    $this->username = trim($username);
    $this->email = trim($email);
    $this->email_repeat = trim($email_repeat);
    $this->password = $password;
    $this->password_repeat = $password_repeat;
    $this->ip = $ip;
    $this->reCaptcha_response = $reCaptcha;
    $this->reCaptcha = new ReCaptcha(GOOGLE_CAPTCHA_SECRET); //the API secret is in the config.php file

    $this->verifyEmail();
    $this->verifyUsername();
    $this->verifyPassword();
    $this->validateReCaptcha($this->reCaptcha_response, $this->ip);

    $this->db->insertRow("INSERT INTO users (username, password, email) VALUES (?, ?, ?)", [$this->username, $this->password, $this->email]);
}

public function verifyEmail () {
    if(empty($this->email) || empty($this->email_repeat)) {
        throw new \Exception('Email address is empty');
    }

    $isTaken = $this->db->getRow("SELECT COUNT(*) as count FROM users WHERE email= ?", [$this->email]);
    if($isTaken->count > 0){
        throw new \Exception('This email is taken');
    }
}


private function verifyUsername () {
    if(strlen($this->username) < 3 || strlen($this->username) > 15) {
        throw new \Exception('Username must be between 3 and 15 symbols');
    }

    $isTaken = $this->db->getRow("SELECT COUNT(*) as count FROM users WHERE username= ?", [$this->username]);
    if($isTaken->count > 0){
        throw new \Exception('This username is taken');
    }
}

控制器:

public function register ()
{
    if($this->post != null) {
        try {
            $register = $this->tableRegister->register(
                $_POST['username'],
                $_POST['email'],
                $_POST['email_repeat'],
                $_POST['password'],
                $_POST['password_repeat'],
                $_SERVER['REMOTE_ADDR'],
                $_POST['g-recaptcha-response']
            );
        } catch (\Exception $err) {
            $this->flashMessage->error($err->getMessage());
        }
    }
    $this->renderView('users/register');
}

正如您在模型中看到的那样,validateEmailvalidateUsername 两种方法都会遍历数据库并检查电子邮件或用户名是否已被占用。如果他们都被占用,我想捕获这两个异常,以及可能发生的所有其他异常 - 如果电子邮件被占用,如果用户名被占用,如果用户名无效......一切。目前我的脚本在第一个异常处结束。我怎样才能做到这一点?

您的模型 register 函数中需要有一个 try-catch,例如

public function register (string $username, string $email, string $email_repeat, string $password, string $password_repeat, string $ip, string $reCaptcha) {
    try{
        $this->username = trim($username);
        $this->email = trim($email);
        $this->email_repeat = trim($email_repeat);
        $this->password = $password;
        $this->password_repeat = $password_repeat;
        $this->ip = $ip;
        $this->reCaptcha_response = $reCaptcha;
        $this->reCaptcha = new ReCaptcha(GOOGLE_CAPTCHA_SECRET); //the API secret is in the config.php file

        $this->verifyEmail();
        $this->verifyUsername();
        $this->verifyPassword();
        $this->validateReCaptcha($this->reCaptcha_response, $this->ip);

        $this->db->insertRow("INSERT INTO users (username, password, email) VALUES (?, ?, ?)", [$this->username, $this->password, $this->email]);
    } catch(\Exception ex){
        //handle error
        throw new \Exception("Error registering user"); //this will pass the exception up to the calling method instead of just killing the page
    }
}

如果 verifyEmailverifyUsername 抛出错误,这些错误将停止执行其余代码。由于未正确处理,这将停止执行整个页面。

希望对您有所帮助!

When an exception is thrown, code following the statement will not be executed, and PHP will attempt to find the first matching catch block. If an exception is not caught, a PHP Fatal Error will be issued with an "Uncaught Exception ..." message, unless a handler has been defined with set_exception_handler() (source).

这里一个好的解决方案是为模型添加 errors 属性、hasErrorsgetErrors 方法。这将允许您存储和处理每个表单域的错误检查。

例如:

public function verifyEmail () {
    if(empty($this->email) || empty($this->email_repeat)) {
        $this->errors['email'] = 'Email address is empty';
        return false;
    }

    $isTaken = $this->db->getRow("SELECT COUNT(*) as count FROM users WHERE email= ?",
       [$this->email]);
    if($isTaken->count > 0){
        $this->errors['email'] = 'This email is taken';
        return false;
    }

    return true;
}

public function hasErrors() {
    return !empty($this->errors);
}

public function getErrors() {
    return $this->errors;
}

对模型中的register方法添加检查:

if (!$this->hasErrors()) {
    $this->db->insertRow("INSERT INTO users (username, password, email) VALUES (?, ?, ?)",
     [$this->username, $this->password, $this->email]);
}

然后在你的控制器中添加检查:

if ($this->tableRegister->hasErrors()) { 
    $this->flashMessage->error('The form has error(s): '
        .implode("; \r\n", $this->tableRegister->getErrors()));
} else {
    // code for user registration here
}