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


![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/46841/53693619-bbf8-752a-d805-036b72a45199.jpeg "1.jpg")

1. [基本設計、ユーザーモデル](http://qiita.com/ShibuyaKosuke/items/f114ffccf441edb2b745)
2. [オートローダー](http://qiita.com/ShibuyaKosuke/items/6109810464a7293293bd)
3. [例外・ログ](http://qiita.com/ShibuyaKosuke/items/88b1305a4ff0c5f3e728)
4. [PDO シングルトン　SQLインジェクション](http://qiita.com/ShibuyaKosuke/items/094df7f399912ae7df56)
	* [汎用データベース・クラス作成](http://qiita.com/ShibuyaKosuke/items/8502492ac024362b528d)

5. [ユーザーモデルの作成](http://qiita.com/ShibuyaKosuke/items/81c556d836d70a29c5f3)
6. [クラスの継承](http://qiita.com/ShibuyaKosuke/items/490ffa6a92670cf6c644)
7. [テンプレート・クラスの実装](http://qiita.com/ShibuyaKosuke/items/803dc58a23601118942e)
8. [アカウントロック機能の実装](http://qiita.com/ShibuyaKosuke/items/e890becdb8193d3def05)
9. [メール送信機能の実装](http://qiita.com/ShibuyaKosuke/items/78c8673782ebbf51584b)
10. [アカウントロック解除機能の実装](http://qiita.com/ShibuyaKosuke/items/ee4b1896071eeca37628)
11. [CSRF対策](http://qiita.com/ShibuyaKosuke/items/8100e304e4447e44e98c)

今回は、[例外](http://php.net/manual/ja/language.exceptions.php)処理を実装して行きます。画像は特に関係ありません。おそらく見覚えのあり方は若くても30代？
エクセルとか使っているとよく登場しました…。

例外とは…

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

Java ではと書いてありますが、PHPでも[Exception](http://php.net/manual/ja/class.exception.php)クラスを呼び出します。

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

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

「スローされる」は「発生させる」と置き換えて読むと理解しやすいかもしれません。「サブクラス」とはクラスを[継承](http://php.net/manual/ja/language.oop5.inheritance.php)したクラスのことです。

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

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

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

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

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

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

##InvalidErrorExceptionの実装##

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

[\#1](http://qiita.com/ShibuyaKosuke/items/f114ffccf441edb2b745)で説明した様に、namespace をつけて定義します。

```php:InvalidErrorException.class.php
<?php

namespace MyApp\common;

class InvalidErrorException extends \Exception
{

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

}

```

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

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

```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];
		}
	}

}
```

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

```php: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の実装##

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

```php: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 も実装して行くと、以下のようになりますね。

```php: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)
	{

	}

}
```

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