Help us understand the problem. What is going on with this article?

PHPでログイン機能を実装するチュートリアル #3

More than 3 years have passed since last update.

1.jpg

  1. 基本設計、ユーザーモデル
  2. オートローダー
  3. 例外・ログ
  4. PDO シングルトン SQLインジェクション

  5. ユーザーモデルの作成

  6. クラスの継承

  7. テンプレート・クラスの実装

  8. アカウントロック機能の実装

  9. メール送信機能の実装

  10. アカウントロック解除機能の実装

  11. CSRF対策

今回は、例外処理を実装して行きます。画像は特に関係ありません。おそらく見覚えのあり方は若くても30代?
エクセルとか使っているとよく登場しました…。

例外とは…

プログラムの実行時に、何らかの例外的な事象が発生すること。Javaではシステムエラー以外のエラー(実行時例外、入出力例外など)に対して例外処理のクラスが初めから用意されており、例外が発生した場合にはこれらのクラスを呼び出して処理する。(コトバンクより)

Java ではと書いてありますが、PHPでもExceptionクラスを呼び出します。

http://php.net/manual/ja/class.exception.php

スローされるオブジェクトは、Exception クラスあるいは Exception のサブクラスのインスタンスでなければなりません。 それ以外のオブジェクトをスローしようとすると PHP の Fatal Error が発生します。

「スローされる」は「発生させる」と置き換えて読むと理解しやすいかもしれません。「サブクラス」とはクラスを継承したクラスのことです。

例外処理を適切にハンドリングしておくと、エラーや不具合の原因追求の手助けとなります。
エラーや不具合は多種多様です。軽微なものであればユーザーに操作のやり直しを促すだけで回避できるものや、プログラム自体の修正をしなければならない重大なものまで存在します。重大なものであれば、発生したと同時に開発者にメールで通知する必要があるかもしれません。

ここでは、軽微な例外と通常の例外と深刻な例外と大きく3つに分けて実装して行きます。

それぞれ名前をつけましょう。

  1. 深刻な例外: SystemErrorException
  2. 通常の例外: ApplicationErrorException
  3. 軽微な例外: InvalidErrorException

それぞれ例外が発生したときに、どのように扱うかをまとめておきます。

クラス名 ログの書き出し 画面表示する文言 管理者へのメール送信
SystemErrorException する システムエラーが発生しました する
ApplicationErrorException する アプリケーションエラーが発生しました しない
InvalidErrorException しない エラーメッセージをそのまま表示する しない

InvalidErrorExceptionの実装

commonディレクトリ以下に、InvalidErrorException.class.php を作成します。

#1で説明した様に、namespace をつけて定義します。

InvalidErrorException.class.php
<?php

namespace MyApp\common;

class InvalidErrorException extends \Exception
{

    public function __construct($code, \Exception $previous = null)
    {
        parent::__construct($message, $code, $previous);
    }

}

ここで、第1引数に $message をつけていないのは、このコードとメッセージをしっかり管理したいので、別のクラスで一元管理したいからです。

同じく、common 以下に ExceptionCode.class.php を作成します。

ExceptionCode.class.php
<?php

namespace MyApp\common;

class ExceptionCode
{
    //エラーコードを整数で定義する
    const INVALID_ERR = 1000;

    //定数をキーに配列でメッセージを定義する
    static private $_arrMessage = array(
        INVALID_ERR => 'エラーが発生しました。'  //とりあえずのメッセージ
    );

    static public function getMessage($intCode)
    {
        if (array_key_exists($intCode, self::$_arrMessage)) {
            return self::$_arrMessage[$intCode];
        }
    }

}

メッセージはコンストラクタ内から、コードで呼び出します。

InvalidErrorException.class.php
<?php

namespace MyApp\common;

class InvalidErrorException extends \Exception
{

    public function __construct($code, \Exception $previous = null)
    {
        $message = ExceptionCode::getMessage($code);//追記
        parent::__construct($message, $code, $previous);
    }

}

SystemErrorExceptionの実装

基本的には前項のものと同じですが、「メールを送信する」「ログを書く」「表示メッセージは統一する」という点で先ほどとは異なります。

SystemErrorException.class.php
<?php

namespace MyApp\common;

class SystemErrorException extends \Exception
{

    /**
     * コンストラクタ
     * @param type $code
     * @param \Exception $previous
     */
    public function __construct($code, \Exception $previous = null)
    {
        $message = ExceptionCode::getMessage($code);
        self::writeLog($message);
        self::sendMail($message);
        parent::__construct('システムエラーが発生しました。', $code, $previous);
    }

    /**
     * 管理者へメール
     * @param type $message
     */
    static private function sendMail($message)
    {

    }

    /**
     * ログを書く
     * @param type $message
     */
    static private function writeLog($message)
    {

    }

}

メール送信とログについてはから実装にしておきます。このようにしておけば、要件どおりの動きをすることは理解できますでしょうか。

同様に、ApplicationErrorException も実装して行くと、以下のようになりますね。

ApplicationErrorException.class.php
<?php

namespace MyApp\common;

class ApplicationErrorException
{

    /**
     * コンストラクタ
     * @param type $code
     * @param \Exception $previous
     */
    public function __construct($code, \Exception $previous = null)
    {
        $message = ExceptionCode::getMessage($code);
        self::writeLog($message);
        parent::__construct('アプリケーションエラーが発生しました。', $code, $previous);
    }

    /**
     * ログを書く
     * @param type $message
     */
    static private function writeLog($message)
    {

    }

}

次回はデータベース周りの機能について実装して行きます。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away