54187
現在、PHPの勉強としまして、簡易な掲示板のサイトを作成しているのですが、ユーザーが投稿されたコメント欄の削除パスワードを間違えて入力してしまった際に、どのように画面に表示させるか、といった部分でうまくいかず、お力をお貸し頂きたく、ご質問させて頂きました。  
削除パスワードが入力され、データベースに接続し、格納されているコメントの削除処理を記載したコードは、以下の「delete1.php」になります。

```

    <?php 
    include 'bbs_class1.php';
    error_reporting(E_ALL);
    ini_set('display_errors', '1');
    $errs = [];
    $bbs = new Bbs('mysql:host=localhost;dbname=online_bbs;charset=utf8', 'root', '12345', 10);
    if(!empty($_POST)){
    
      $password = filter_input(INPUT_POST,'password');
      $id = intval(filter_input(INPUT_POST,'id'));
    
      if(!$password){
        $errs[] = 'パスワードを入力してください';
      }elseif(!preg_match('/\A[a-z\d]{8,100}+\z/i',$password)){
        $errs[] = 'パスワードは半角英数8文字以上で入力してください';
      }
    
    
      if(!$id){
        $errs[] = 'idが送信されていません';
      }
    
      if(empty($errs)){
        try{
          $bbs->delete($id,$password);
        }catch(PDOException $e){
          echo $e->getMessage();
        }
    
        header('Location:bbs1.php');
        exit();
      }
    
    }
    ?>
    
    <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
      </head>
      <body>
        <p>
          <?php if(!empty($errs)): ?>
            <?php echo implode('<br />',$errs); ?>
            <a href="bbs1.php">戻る</a>
    
          <?php endif;?>
      </body>
      </html>
    
    
```

データベースの接続処理などをまとめたクラスである、「bbs_class1.php」の削除処理、及びデータベース接続処理をまとめたメソッドが以下のコードとなります。

```

    public function delete($id,$password){
    
                $stmt = $this->dbh->prepare("SELECT password FROM post_3 WHERE id = :id");
                $stmt->bindValue(':id',$id,PDO::PARAM_INT);
                $stmt->execute();
                $db_password = $stmt->fetchColumn();
                //var_dump($db_password);
                if(!password_verify($password,$db_password)){
                    throw new Exception('パスワードが違います');
                }
    
                $stmt = $this->dbh->prepare("DELETE FROM post_3 WHERE id = :id");
                $stmt->bindValue(':id',$id,PDO::PARAM_INT);
                $stmt->execute();           
        }
    
```

実は、「delete1.php」の

```

    if(empty($errs)){
        try{
          $bbs->delete($id,$password);
        }catch(PDOException $e){
          echo $e->getMessage();
        }
    
        header('Location:bbs1.php');
        exit();
      }
    
```

こちらの部分におきまして、エラーメッセージを出力させようと思ったのですが、fatalエラーが発生してしまい、エラーメッセージのみを出力させることができません。  
また、try,catch文内のcatchにて、deleteメソッドの「throw new
Exception('パスワードが違います');」ここの部分で例外をスローしたものをメッセージとして出力する処理にした場合、仮に、データベースに接続できないなどの、エラーが発生した場合は、スローした例外と、データベースエラーのどちらのメッセージがdelete1.phpの`catch(PDOException
$e){echo $e->getMessage();}`のメッセージとして出力されるのかなども疑問です...  
どなたか、ご教示いただける方いらっしゃいましたら、ご助言頂けましたら幸いです。

* * *

※以下は頂きましたご回答を踏まえ、修正&追記しましたコードになります。  
まず、新たにパスワード認証用の例外クラスを作成致しました。  
以下は、「exception.php」になります。

```

        <?php
    class PasswordException extends Exception{
      public function __construct($message){
        parent::__construct($message);
      }
    }
    
```

以下はbbs_class1.phpのdeleteメソッドを修正したものになります。

```

    public function delete($id,$password){
    
            $stmt = $this->dbh->prepare("SELECT password FROM post_3 WHERE id = :id");
            $stmt->bindValue(':id',$id,PDO::PARAM_INT);
            $stmt->execute();
            $db_password = $stmt->fetchColumn();
            //var_dump($db_password);
            if(!password_verify($password,$db_password)){
                throw new PasswordException('パスワードが違います');                
            }
    
            $stmt = $this->dbh->prepare("DELETE FROM post_3 WHERE id = :id");
            $stmt->bindValue(':id',$id,PDO::PARAM_INT);
            $stmt->execute();           
    }
    
```

以下は、delete1.phpのdeleteメソッド呼び出し部分を修正したコードになります。

```

    if(empty($errs)){
        try{
          $bbs->delete($id,$password);
        }catch(PDOException $e){
          echo $e->getMessage();
        }catch(PasswordException $e){
          echo $e->getMessage();
          exit();
        }
    
        header('Location:bbs1.php');
        exit();
      }
    
```
CC BY-SA 4.0
2019-04-15T06:49:34.167
54172
2019-04-16T01:08:53.817
2019-04-16T01:08:53.817
32912
32912
question
php
ユーザーの入力間違えによる、エラーの出力方法について
`catch` の仕様として「引数で指示されている種類の例外のみを受け取る」ので、提示コードの `catch (PDOException $e)` は
`PDOException` およびその派生クラスの例外だけを捕捉し、他の種類の例外は捕捉しません。

提示例では、投げている例外が `throw new Exception('パスワードが違います');` なので `PDOException`
には該当せず、よって提示コードだけでは捕捉されません。

`catch` は１か所に複数個書けるので、試してみましょう。

`catch (Exception)`
は「すべての例外」を捕捉するので先に書いた通り「デバッグできなくなる典型コード」となってしまいます。業務例外とシステム例外が区別できるよう
`Exception` を直接使うのでなくて一度派生させて使うほうが良いです。(`PDOException`
はシステム例外、パスワードが違うのは業務例外）とりあえず業務例外専用クラス `MyException` とか作って `throw
MyException(...)` `catch (MyException)` してみましょう。
CC BY-SA 4.0
2019-04-15T09:42:44.430
54187
2019-04-15T09:42:44.430
8589
54172
answer