壊れたメガネ

ホッチキスの達人の意識の高いブログ。

Exceptionについて考えてみた

Exceptionについて考えてみた



前のエントリ、「PHPの出力をキャッシュして、ついでに圧縮はしない。」で扱った@tanatonさんのキャッシュ用クラス OutputのコンストラクタにおけるExceptionの使い方が気になってたのでちょっと考えてみました。
このコンストラクタでのExceptionの使い方には2つの問題があると認識しています。


まずはOutputクラスのコンストラクタ


public function __construct($match_path, $path = './cache', $clevel = Output::CLEVEL_DEFAULT)
{
	$this->now_time = time();
	$this->cache_path = $path.'/'.substr(md5($match_path), 0, 10).'.cache';
	if((is_int($clevel) === false) || ($clevel < 0) || ($clevel > 9)){
		throw new Exception('圧縮レベルがおかしい', 1);
	}
	$this->compress_level = $clevel;

	if($this->cache_check() === true){
		// キャッシュ出力
		$this->cache_output();
		// コンストラクタ終了
		throw new Exception('キャッシュを出力したよ', 0);
	}
	// 出力のバッファリング開始
	ob_start();
}


異なる例外の区別の方法



このメソッドは異なる2つの場合に例外を投げますが、いづれの場合もそれはExceptionクラスとなっています。
このAPIを用い、例外処理を書く場合一つのcatchブロックで2つの例外を扱わなければなりません。
即ち、異なる例外を判別する為に、投げられたインスタンスからエラーコードを取り出し switch なり、 if なりで分岐、処理しなければなりません。
これはせっかくのException「オブジェクト」を反古にしており、PHPの旧来のエラーチェックのやり方(単なるスカラーにその関数・メソッドの成功やエラーとその意味を含めるやり方)に成り下がっています。
替わりにどうするかというと、それぞれの異常を表現したExceptionのサブクラスを用意するべきです。
(例えば IllegalCompressionLevelException と CacheCheckException みたいなもの。)


そもそもExceptionを用いる必要が無い



そもそも if($this->cache_check() === true) のブロック内でExceptionを用いる必要が無い様に見えます。
使い方を見るに、このブロックを抜けた後の ob_start() のコールを避けるためにこのようにしていると思われます。
この場合Exceptionでgoto文的にジャンプする必要は無く、ただreturnすればいいだけです。
別にgoto文が悪いとはいいません。Exceptionはエラーを扱う為に用意された機構なので、基本はエラーを扱う為に用いるべきだと考えています。


お前なんでそんなに偉そうなの?と思った方へ



このエントリは私が偉そうに@tanatonさんの書いたコードに勝手に文句を付けています。
おそらく多くの方が「お前何様よ。なんでそんなに偉いの?」と思ったことでしょう。
私は単なる便秘気味のプログラマです。糞みたいな単なる作業員にも発言の自由ぐらいあってもいいはずです。
発言には責任を持つつもりであります。(ときどき免責事項とか書きますが。。。)


参考