質問
例外メッセージの作成時に有用なデバッグ情報を強制するためにどれだけの労力を費やすべきか、またはユーザーに正しい情報を提供するか、情報収集を例外ハンドラーに延期するだけでよいか?
次のような例外を実行する多くの人々を見ています:
throw new RuntimeException('MyObject is not an array')
またはデフォルトの例外を、あまり実行しないが例外の名前を変更するカスタム例外で拡張する:
throw new WrongTypeException('MyObject is not an array')
しかし、これは多くのデバッグ情報を提供しません...そして、エラーメッセージでどんな種類のフォーマットも強制しません。したがって、2つの異なるエラーメッセージを生成するまったく同じエラーが発生する可能性があります。たとえば、「データベース接続に失敗しました」などです。 vs" dbに接続できませんでした"
確かに、トップにバブルすると、スタックトレースが出力されますが、これは便利ですが、常に必要なことをすべて教えてくれるとは限らず、通常var_dump()からシュートを開始しなければなりません何が間違っていてどこで...を発見するためのステートメント。ただし、これはまともな例外ハンドラーで多少相殺できます。
以下のコードのようなものについて考え始めています。ここで、正しいエラーメッセージを生成するために必要な引数を提供するために例外のスローを必要にします。私はこれがその方法になるかもしれないと思っています:
- 最低限必要な情報を提供する必要があります
- やや一貫したエラーメッセージを生成します
- 例外メッセージのテンプレートはすべて1つの場所(例外クラス)にあるため、メッセージを簡単に更新できます...
しかし、使用が難しく(例外の定義を調べる必要がある)、他のプログラマーが提供された例外を使用するのを妨げる可能性があるという欠点があります...
このアイデアについてコメントをお願いします&一貫性のある柔軟な例外メッセージフレームワークのベストプラクティス。
/**
* @package MyExceptions
* MyWrongTypeException occurs when an object or
* datastructure is of the incorrect datatype.
* Program defensively!
* @param $objectName string name of object, eg "\$myObject"
* @param $object object object of the wrong type
* @param $expect string expected type of object eg 'integer'
* @param $message any additional human readable info.
* @param $code error code.
* @return Informative exception error message.
* @author secoif
*/
class MyWrongTypeException extends RuntimeException {
public function __construct($objectName, $object, $expected, $message = '', $code = 0) {
$receivedType = gettype($object)
$message = "Wrong Type: $objectName. Expected $expected, received $receivedType";
debug_dump($message, $object);
return parent::__construct($message, $code);
}
}
....
/**
* If we are in debug mode, append the var_dump of $object to $message
*/
function debug_dump(&$message, &$object) {
if (App::get_mode() == 'debug') {
ob_start();
var_dump($object);
$message = $message . "Debug Info: " . ob_get_clean();
}
}
次に、次のように使用します:
// Hypothetical, supposed to return an array of user objects
$users = get_users(); // but instead returns the string 'bad'
// Ideally the $users model object would provide a validate() but for the sake
// of the example
if (is_array($users)) {
throw new MyWrongTypeException('$users', $users, 'array')
// returns
//"Wrong Type: $users. Expected array, received string
}
また、カスタム出力例外ハンドラーでnl2brのような処理を実行して、HTML出力に適したものにすることもできます。
読書中: http://msdn.microsoft.com/en-us/library/cc511859。 aspx#
そして、このようなことについて何も言及されていないので、たぶんそれは悪い考えです...
解決
Krzysztofのブログに関するアドバイスを強くお勧めします。そして、あなたの場合、彼が使用エラーと呼ぶものに対処しようとしているように見えることに注意してください。
この場合、必要なのは、それを示すための新しい型ではなく、原因のより良いエラーメッセージです。そのようなヘルパー関数として:
- テキスト文字列を生成して例外に置きます
- 例外とメッセージ全体を生成する
必要なものです。
アプローチ1はより明確ですが、もう少し冗長な使用につながる可能性があります。2は逆で、より明確ではないがより簡潔な構文を使用します。
関数は非常に安全である必要があり(関連する例外を決して発生させてはならない)、特定の合理的な使用においてオプションであるデータの提供を強制しないことに注意してください。
これらのアプローチのいずれかを使用することにより、必要に応じて後でエラーメッセージを国際化しやすくなります。
最低でもスタックトレースは関数と、場合によっては行番号を提供します。そのため、そこから簡単に解決できない情報を提供することに集中する必要があります。
他のヒント
Krzysztofのブログに関するアドバイスを損なうことはありませんが、ここではカスタム例外を作成する非常に簡単な方法を示します。
例:
<?php
require_once "CustomException.php";
class SqlProxyException extends CustomException {}
throw new SqlProxyException($errorMsg, mysql_errno());
?>
その背後にあるコード(どこかで借りたコード、それが誰かに謝罪します)
<?php
interface IException
{
/* Protected methods inherited from Exception class */
public function getMessage(); // Exception message
public function getCode(); // User-defined Exception code
public function getFile(); // Source filename
public function getLine(); // Source line
public function getTrace(); // An array of the backtrace()
public function getTraceAsString(); // Formated string of trace
/* Overrideable methods inherited from Exception class */
public function __toString(); // formated string for display
public function __construct($message = null, $code = 0);
}
abstract class CustomException extends Exception implements IException
{
protected $message = 'Unknown exception'; // Exception message
private $string; // Unknown
protected $code = 0; // User-defined exception code
protected $file; // Source filename of exception
protected $line; // Source line of exception
private $trace; // Unknown
public function __construct($message = null, $code = 0)
{
if (!$message) {
throw new $this('Unknown '. get_class($this));
}
parent::__construct($message, $code);
}
public function __toString()
{
return get_class($this) . " '{$this->message}' in {$this->file}({$this->line})\n"
. "{$this->getTraceAsString()}";
}
}
例外階層の設計方法を参照してください「Framework Design Guidelines」の共著者であるKrzysztof Cwalinaのブログ。
ユーザーが「正しいことをする」ことを決して信用せず、デバッグのための情報を含めてください。情報が必要な場合は、自分で情報を収集し、アクセス可能な場所に保存する必要があります。
また、述べたように、何かをするのが難しい場合、ユーザーはそれを避けますので、繰り返しますが、善意と送信する必要のある知識に依存しないでください。
この考え方は、情報を収集して記録する方法を意味します。つまり、どこかでvar_dump()を使用することを意味します。
また、Mark Harrisonが言ったように、エラーメッセージをどこかに簡単に送信できるボタンは、あなたにとってもユーザーにとっても素晴らしいものです。エラーの報告が簡単になります。あなたは(受信者として)多くの重複を取得しますが、重複情報は情報がないよりも優れています。
追加する詳細にかかわらず、確認してください
- すべてを簡単にカットアンドペーストするか、
- エラーを報告するボタンがあります