php_study 日記: 例外処理
php_study 日記: 例外処理
2011 年 12 月 21 日
##例外処理
きちんと設計されたソリューションを作成しましたが、プログラムの実行中にまださまざまな問題が発生する可能性があります。プログラムの実行中に、0による除算のオーバーフロー、配列の範囲外、ファイルが見つからないなどの異常なイベントが発生すると、プログラムの正常な動作が妨げられます。プログラムを設計する際には、プログラムが堅牢に動作するように、発生する可能性のあるさまざまな異常事態を予測し、それに応じて対処する耐障害性を十分に考慮する必要があります。
>前の例外処理メソッド
1. PHP.ini が表示できるエラーの種類。
2.PHP.ini の Error_reporting は、クライアントに出力されるメッセージの種類を制御します。 php.ini の推奨構成は次のとおりです。
error_reporting = E_ALL; は、すべての情報を出力することを意味します。
error_reporting = E_ALL&~E_NOTICE; は、プロンプトを除くすべてのエラーを出力することを意味します。
error_reportin = E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE _ERROR: すべての ERROR 情報を出力することを示します。
3. php.ini では、display_errors で上記で設定したエラー情報をユーザー端末に出力するかどうかを設定できます
Display_errors=On をユーザー端末に出力します (コードのデバッグ時にオンにすると非常に便利です)
Display_errors=OFF メッセージはユーザーに出力されません (最終的にユーザーに公開するときに忘れずにオフに変更してください)
注:
PHP では、エラー処理の要件が非常に緩和されています。 PHP システムは、致命的なエラーが発生しない限り、プログラムの実行を継続しようとします。
php.ini ファイルでエラー メッセージの表示レベルを調整するだけでなく、PHP コードでメッセージの表示レベルをカスタマイズすることもできます。 PHP では、このプログラムでメッセージの表示レベルをカスタマイズする機能を実装するための関数 error_reporting() を提供しています。
関数構文: int error_reporting([int level])
関数の説明: この関数を使用して、現在の PHP ページのエラー メッセージの表示レベルを定義します。パラメータレベルはバイナリマスク結合方式を使用します。具体的な結合方式は表で確認します。
> die() を使用してプログラムを終了する
これまでのプログラム開発プロセスでは、例外が発生したときにプログラムの実行を停止し、現在のプログラムを終了するには die() を使用するのが最も一般的な例外処理方法でした。終了するプログラム。
Daxin プログラム プロジェクトは通常、基本クラスをフォルダーに個別に格納し、各クラスは PHP ファイルとして個別に格納され、PHP ファイルにはクラス名に基づいた名前が付けられます。
Web サイトの mail_class ディレクトリに基本クラス ライブラリのファイルが保存されているとします。このディレクトリには、SMTP 機能を提供する基本クラスまたはインターフェイス プログラムである stmp.php ファイルがあり、その他のファイルもあります。クラス名とファイル名を持つサブクラス ファイル:normal.php (通常の電子メールは mail() 関数を通じて送信されます)、auth.php (電子メールは送信者の身元を確認する必要があるサードパーティの SMTP サーバーを通じて送信されます) )、MIME.php (複雑なグラフィックおよびテキストの電子メールが送信されます) など。
Dir . "/" . $smtp . ".php";
if (!file_exists($path))
die(" . $path . ".n" );
}
require_once $path;
if(!class_exists($smtp))
{
die("class".
}
$ret = new $ smtp();
if (!($ret instanceof SMTP))
{
die($smtp . " は SMTP クラス .n" ではありません);
return $ret ;
}
}
$smtp = new SMTPManager() ?>
この例では、クラスの検索が失敗すると、スクリプトの実行が終了します。コード。しかし、このコードは柔軟性に欠けており、必要なクラス ファイルが見つからないときにプログラムの実行をすぐに停止したくない場合もあります。
>trigger_error() を使用してカスタム警告情報を表示します。
カスタマイズされた警告を提供するために、trigger_error 関数が 4.01 以降のさまざまな PHP バージョンで提供されています。これにより、エラーの処理が向上し、顧客のプログラマがエラーを処理しやすくなります。
関数の構文: bool trigger_error(string $error_msg[,int $error_type])
関数の説明: この関数は、ユーザー定義レベルの警告、プロンプト、エラー メッセージを提供するために使用されます。trigger_error() はエラー メッセージを受け取ります。 $error_msg と定数 $error_type がパラメータとして使用されます。使用できる $error_type 定数は、E_USER_ERROR (致命的エラー)、E_USER_WARNING (警告レベルの非致命的エラー)、E_USER_NOTICE (プロンプト メッセージ) の 3 つです。
Dir . "/" . ".php";
if (!file_exists($path))
{
trigger_error("" . $path . ".n" ,E_USER_ERROR);
require_once $path;
if(!class_exists($smtp))
{
trigger_error("class". $smtp . "は存在しません" ,E_USER_ERROR);
}
$ret = new $smtp();
if (!($ret instanceof SMTP))
{
trigger_error($smtp . " は SMTP クラスではありません。n",E_USER_ERROR);
}
return $ret;
}
}
function ErrorHandler($errnum,$errmsg,$ file,$line)
{
if($errnum == E_USER_ERROR)
{
echo "ERROR:$errmsgn
"
echo "FILE:$filen
; ";
echo "LINE: $linen
";
exit();
}
}
$handler = set_error_handler('ErrorHandler');
$smtp = new SMTPManager();
$smtp->GetObject("auth");
?>
この例では、例外を処理するために set_error_handler() カスタム ハンドラー関数を使用します。 trigger_error()関数はエラーをスローします。 set_error_handler() は関数名をパラメータとして受け入れます。エラーが発生した場合、パラメータとして使用される関数が呼び出され、エラーが処理されます。この関数は、エラー フラグ、エラー メッセージ、エラー ファイル、エラーが発生した行数の 4 つのパラメータを渡す必要があります。配列を set_error_handler() に渡すこともできます。配列の最初の要素はエラー ハンドラーが呼び出されるオブジェクトでなければならず、2 番目の要素はエラー処理関数の名前です。私たちのエラー ハンドラーは非常にシンプルな設計になっており、エラー情報の記録の追加、デバッグ データの出力など、改善の余地があります。しかし、これは依然として非常に大まかなエラー処理方法であり、E_USER_ERROR エラーの捕捉など、考慮されたエラー状況にのみ限定できます。スクリプトの実行を中止するために exit() や die() を使用しないことを望んでいるかもしれません。しかし、これを実行すると、非常に微妙なバグが発生する可能性があり、終了するはずのプログラムが引き続き実行されます。
>エラーの特定を随時判断
##戻り値による処理方法は確かに有効であり、環境に応じて複数のエラーに対応でき、エラー発生時に即座にプログラムを停止する必要はない。最初のエラーが発生します。実行されますが、多くの欠点があります。
#プログラムが複雑
#信頼性が低い
#リターン情報が限られている
#リターンコードの標準化が難しい
を使用する利点「false」のようなエラー フラグは直感的ですが、明らかに与えられた情報量では false が返される原因となったエラーがどのリンクで発生したかを知ることができないため、より詳細なエラー情報を確認できるように error_str 属性を追加しました。エラー発生後に出力されます。
error_str = get_class($this). "::{$method}(): $msg";
}
public function getError()
{
return $this-> error_str;
}
public function getObject($smtp)
$path = $this->Dir .
.if( !file_exists($path))
{
$this->setError(__FUNCTION__, "Cannot find" . $path . ".n");
return false; require_once $path;
if(!class_exists($smtp))
{
$this->setError(__FUNCTION__, "クラス" . $smtp . "存在しません。n"); > false を返します;
}
$ret = new $smtp();
if(!($ret instanceof SMTP))
smtp . "は SMTP クラスではありません|");
return false;
}
return false;
return false;
{
// 通常の値を書きます。ここでコードを処理します
}
else
{
echo $smtp- >getError() .
die("getObject Error!");
?>
この単純なメカニズムにより、setError() はエラー情報を記録し、他のコードは getError() を使用してスクリプト エラー関連の情報を取得できます。この関数を抽出して最も基本的なクラスに配置し、他のすべてのクラスがこのクラスを継承できるようにすることで、エラーを均一に処理できます。そうしないと混乱が発生する可能性があります。ただし、実際の開発では、プログラム内のすべてのクラスを同じクラスから継承させることは非常に困難ですが、インターフェイスを介して行うことは可能であり、そうしないとサブクラスの一部の独自の機能を実現できません。
PEAR 拡張クラス ライブラリを使用して例外を処理します
最後の方法は、PHP4 で拡張された PEAR 基本クラス ライブラリを使用して例外を処理することです。最も重要なメソッドは、エラーが発生した場合にエラーを返すことができる raiseError() です。 PEAR_Error オブジェクトが発生する場合、その使用法は次のとおりです:
PEAR::raiseError(string $message[,int $code[,int $mode[,int |array $options[,mixed $userinfo[,string $error_class[,boolean] $ Skipmsg]]]]])
パラメータの説明
文字列 $message: エラー メッセージ、左側が空の場合、デフォルトのエラー メッセージは「不明なエラー」
整数 $code: エラー コード
整数 $ モード: エラーモード。 (一部の定数は自分でテーブルを調べて設定する必要があります)
Mixed$options: エラー コード。 (呼び出しメソッドを覚えておいてください)
混合 $userinfo: 追加のユーザー情報を保存します。
string $error_class: エラーオブジェクトのエラークラス名。
boolean $skipmsg: カスタム クラスのコンストラクターがエラー メッセージを受け入れることができない場合は、このパラメーターを使用します。 $error_class パラメーターなしで $skipmsg パラメーターを使用しないでください。機能しません。
エラーが発生する可能性のあるコードを実行した後、PEAR の isError() メソッドを使用してエラーがあるかどうかを検出する必要があります。また、PEAR_Error の getMessage() を使用して最新のエラー メッセージを取得できます。 PEAR::isError() は重要な場所で使用する必要があることに注意してください。
IsError() メソッドは、変数が PEAR_Error オブジェクトであるかどうかを検出し、オプションで明確なエラー メッセージまたはコードを含みます。その使用法は次のとおりです:
boolean PEAR::isError(mixed $data[,mixed $msgcode])
パラメータの説明:
mixed $data: チェックされた値
mixed $msgcode: 追加のエラー情報またはテストするコード。
error_str = get_class($this) . "::{$method}():$msg";
}
public function GetError()
{
return $this-> error_str;
}
public function GetObject($smtp)
$path = $this->Dir .
.if( !file_exists($path))
{
return PEAR::RaiseError("Cannot find" . $path .".n");
}
require_once $path; !class_exists($smtp))
{
return PEAR::RaiseError("class" . $stmp ."does notexist.n")
}
$ret = new $smtp( );
if(!($ret instanceof SMTP))
{
return PEAR::RaiseError($smtp . "は SMTP クラス .n ではありません") // 返される可能性があります
}
return $ret; // 別の戻り値。
}
}
$smtp = new SMTPManager();
if(PEAR::isError($smtp))
{
echo $cmd->getMessage() 。 "n
";
exit;
}
else
{
// ここに通常の処理コードを書きます。
}
?>
Pear_Error はエラー フラグであり、エラーに関する特定の情報が含まれており、顧客のコードに非常に役立ちます。オブジェクト値を返すことでプログラムの問題に柔軟に対応できますが、その getObject() メソッドには 2 つの出口があり、どちらもオブジェクトであるため、場合によっては混乱が生じ、「インターフェイスが汚染される」という副作用が発生する可能性があります。
>PHP5 の例外処理
過去に必要だった例外処理の仕組みを振り返る
#クライアントコードにエラーマークを付けるメソッドを許可する
複数のエラー条件を判定できる同時に、エラー報告とプログラム処理フローを分離します。
#戻り値は独立した型である必要があり、通常の戻り値の型と混同されず、インターフェイスが汚染されることはありません。
PHP5 は、これらの目的を達成するためにオブジェクト指向の例外処理メカニズムを提供します。
>Exception classException
例外 classException の属性とメソッドの定義:
Message = $message;
}
$this->code = $code; //デフォルトのエラー コードは 0
$this->file = __FILE__; // ファイル名
$this->line = __LINE__; // 行番号
$this->trace = debug_backtrace(); > $this->string = StringFormat($this);
}
// エラーメッセージを取得
final public function getMessage()
{
return $this->message ;
}
//エラーコード
final public function getCode()
{
return $this->code;
}
//例外が発生したファイル
final public function getFile()
{
return $this->file;
}
//例外が発生した行数
final public function getLine()
{
return $this->line;
}
// 例外の各ステップのルートを追跡し、配列に格納し、配列を返します
final public function getTrace()
{
Return $this->trace;
}
// getTrace() と同じ関数ですが、配列内の要素を文字列に変換して特定の形式で出力できます。 format
final public function getTraceAsString( )
{
}
//
public function __toString()
{
return $this->string;
}
?> ;
スクリプトで例外が発生すると、このオブジェクトをインスタンス化できます。
$ex = new Exception("Could not open $this->file"); > PHP5 では、Exception クラスを定義するために上記のコードを記述する必要はありません。このクラスはすでに PHP5 に組み込まれています。例外がトリガーされた場合は、直接例外を生成するのではなく、throw キーワードを使用することをお勧めします。例外オブジェクトのインスタンス。
>例外スローキーワード throw
例外オブジェクトを生成し、それをランタイム システムに送信するプロセスを例外のスローと呼びます。ランタイム システムはメソッドの呼び出しスタックを検索し、例外を生成したメソッドから開始して、対応する例外処理を含むメソッドが見つかるまで遡ります。このプロセスは例外のキャッチと呼ばれます。
スローの使用法は次のとおりです:
throw new Exception("Exception Message",2);
>例外キャプチャ try-Catch ステートメント
例外をスローする可能性のあるプログラム コードはすべて try ステートメントを使用する必要があります。 throw が例外をスローすると、プログラムは throw ステートメントの直後に終了し、その後のステートメントは実行されなくなり、その代わりに、それを含むすべての try ブロック (おそらく上位レベルの呼び出し関数内) が内側から外側へ検索されます。それに一致する項目。catch 句の try ブロック。
catch ステートメントは、スローされる可能性のある例外を処理するために使用されます。 catch ステートメントのパラメータはメソッド宣言と似ており、例外タイプや例外オブジェクトが含まれます。例外の種類は、catch ステートメントによって処理される例外の種類を指定する Exception クラスのサブクラスである必要があります。例外オブジェクトは、try で指定されたコード ブロック内のランタイム システムによって生成され、キャプチャされます。オブジェクト。ここで Object メソッドを呼び出すことができます。
try-catch ステートメントの構文は次のとおりです。
try
{
// 例外が発生する可能性のあるステートメント
}
catch (例外タイプの例外インスタンス)
{
// 例外処理ステートメント
}
インターセプト:
try
{
$smtp = new SMTPManager()
$mail = $smtp->getObject('MIME) ') ;
}
catch (Exception $e)
{
print $e->getMessage();
exit();ブロックは生成されません。 何らかの例外が発生した場合、try ブロックは正常に完了し、catch ブロックの内容は実行されません。
try ブロックが例外をスローした場合、例外をキャッチできる catch ブロックをすぐに検索し、対応する catch ブロック コードを実行して、try-catch ブロックから飛び出して実行を継続します。 try ブロックでスローされた例外に続くコードはスキップされます。
try ブロック内の例外を catch ブロックでキャッチできない場合、その例外はシステムにスローされ、システムの致命的なエラーが発生し、コードは終了します。
catch では、例外タイプの後に変数が続き、メモリ内でキャプチャされた例外インスタンスを指します。
try ブロック内のステートメントが 3 つ以上の例外をスローする可能性がある場合、 throw new Exception($message, $code) を使用するときに、2 番目のパラメーター $code で例外コードを指定し、catch でそれを決定できます。 block 異なる例外コードは個別に処理されます。
異なるタイプの例外をそれぞれ処理するために複数の catch ステートメントが存在する場合があります。複数の拡張例外処理クラスがある場合、実行中のシステムは各例外タイプを一致させるために複数の catch ステートメントを使用することがよくあります。タイプに一致する catch ステートメントが見つかるまで検出されます。各 catch ステートメントのパラメータは、一致するテスト条件のようなもので、最初に一致した catch ステートメントが実行され、他の catch ステートメントは実行されません。ここで、型の一致とは、catch によって処理される例外の型が、生成された例外オブジェクトまたはその親クラスの型とまったく同じであることを意味します。したがって、catch ステートメントの順序は特殊から一般、および特殊に対する catch ステートメントである必要があります。例外は前からアンロードし、一般的な例外の catch ステートメントを後ろに書く必要があります。
1 つの catch ステートメントを使用して複数の例外タイプを処理することもできます。この場合、その例外タイプのパラメーターは、プログラミングでは、catch ステートメントの例外である必要があります。特定の状況に応じて選択されます。
> 例外処理関数の設定 Set_Exception_handler
一般に、下位互換性を維持するために、Try-catch を使用してスローによってスローされる例外を処理します。ただし、これらの関数を使用するために、新しい拡張機能がカスタマイズされています。以前に紹介した set_error_handler() と同様に、PHP では、例外を自動的にキャッチして処理するために、try-catch 関数を使用せずにカスタム拡張機能を指定する方法も提供されています。この関数は set_Exception_handler() によって提供されます。
set_Exception_handler() を使用する場合、例外をキャッチするために指定する関数定義コードを set_Exception_handler() の前に配置し、関数名を set_Exception_handler() のパラメータとして指定する必要があります。
getMessage() . "
例外コード : " . $e->getCode()
. "
FileName: " . : " . $e->getLine() . "
Exception Trace: " . $e->getTraceAsString();
}
// 処理がキャッチされない(try..catch がキャッチされない)実行済み) 操作) 例外
// カスタム例外処理関数 test_error_exc は set_Exception_handler() より前になければなりません
set_Exception_handler('test_error_Excepts');
function file_open()
{
if(!file_exists ($f))
{
throw new Exception("ファイルが見つかりません!",1);
}
if(!fopen($f,"r"))
{
throw new Exception("ファイルオープンエラー!",2);
}
}
file_open("test.htm");
> 例外情報を完了します。 > Exception クラスとそのサブクラスには、各メソッドで例外を引き起こした詳細のすべての層を返すことができる getTraceAsString() メソッドがあり、getTrace() メソッドは、より詳細な例外情報を提供する多次元配列を返します。には例外が発生した場所が含まれ、2 番目の要素には、最高レベルの呼び出しまでの外部メソッド呼び出しの詳細が含まれます。この配列の各要素はそれ自体が配列であり、次の主要な要素が含まれています。
KEY:
file: 例外を生成したファイル
line: 例外を生成したクラスメソッドの行番号
function: 例外を生成した関数/メソッド
class:呼び出されるメソッドのクラス
Type: 呼び出しの種類: "::" は静的クラス メンバーの呼び出しを意味します "->" はインスタンス化呼び出しを意味します (最初に生成されたオブジェクトをインスタンス化してから呼び出します)
args: クラス メソッドパラメータを受け取ります
>拡張例外処理クラス
PHP5 には、Exception クラスのいくつかの組み込みサブクラスも用意されています。LogicException と RuntimeException という 2 つの直接サブクラスがあり、それぞれ論理例外と実行例外を表します。
LogicException サブクラスは、多くの論理例外サブクラスを派生しました。
RuntimeException サブクラスは、多くのランタイム例外サブクラスを派生します。
他のカスタム例外クラスを追加することもできます。これらのクラスは、Exception クラスまたはそのサブクラスから継承する必要があります。
公式プロジェクトでは、例外がスローされると、複数の異なる catch ブロックを使用して一致を検出します。さらに、プログラムがデバッグ モードで実行されているかどうかにかかわらず、異なる処理メカニズムが追加され、同じ catch ブロックが異なる例外コードに従って例外を個別に処理します。
Dir . "/" . ".php";
if(!file_exists($path))
{
throw new SMTPException("Cannot find" . $path . ") n");
}
require_once $path;
if(!class_exists($smtp))
{
throw new IllegalException("class" . $smtp . "は存在しません。 n",101);
}
$ret = new $smtp();
if(!($ret instanceof SMTP))
{
throw new IllegalException($smtp . "は SMTP クラスではありません。.n",102);
}
return $ret;
}
}
try
{
$smtp = new SMTPManager();
$mail = $smtp->getObject('normal');
}
catch(SMTPException $e) // 最初の catch ブロック
{
if($debug)
{ // デバッグモード
echo $e->getMessage();
exit();
else
{ // ウェブサイト実行モード、デバッグ情報は出力されません
exit();
}
}
catch (IllegalException $e) // 2 番目の catch ブロック
{
if ($debug)
{ // デバッグ モード
switch($e->getcode())
{
case 101:
//ファイルは存在するがクラスが存在しない場合のコードの処理
echo $e->getMessage ( ; ->getMessage(); // 利用可能なオブジェクト インスタンスがありません。終了するには exit() が必要です
exit();
デフォルト:
// その他のデフォルト条件
Break;
}
}
}
catch (Exception $e) //3 番目の catch ブロック
{
if($debug)
{ //デバッグモード
echo $e-> ;getMessage();
exit();
}
else
{
exit();
と同じ名前のファイルがあった場合smtp_class フォルダーにクラスが存在する場合、SMTPException がスローされますが、このプログラムはカスタム クラスを 2 つしかスローできません。ただし、最後に Exception 例外を照合するための 3 番目の catch ブロックが提供されます。Exception クラスはすべての例外クラスの基本クラスであり、すべての例外状況に一致するため、この catch ブロックが最初に配置された場合、最初と 2 番目の catch ブロックの前に、この catch ブロックの内容は実行され、他の 2 つの catch ブロックの例外処理コードは実行される機会がありません。
>例外の配信と再スロー
呼び出し側プログラムが発生時にすぐに処理できない例外をトリガーした場合はどうなるでしょうか?同様に、この例外を処理する責任は、現在のメソッドを呼び出した上位レベルのコードに返されます。つまり、例外は catch ステートメントで再度スローされます (再スロー例外とも呼ばれます)。メソッドの呼び出し層チェーンは段階的に渡されます。
>例外処理を正しく使用する
1. すべての例外をキャッチするために 1 つの catch ステートメントを使用することはお勧めできません。最も一般的な状況は、catch(Exception $e) ステートメントです。
その理由を理解するには、catch ステートメントの目的を確認する必要があります。 catch ステートメントは、ある種の例外を予期し、その例外を処理できるようにしたいことを示します。例外クラスの機能は、どの例外を処理したいかを PHP に伝えることです。ほとんどの例外は Exception から直接的または間接的に継承するため、catch(Exception ex) はすべての例外を処理したいと言っているのと同じですが、同じ catch ブロック内で複数のまったく異なる例外を処理するのは不適切です。catch ステートメントで指定する必要があります。特定の例外タイプを指定する必要があり、広すぎる範囲をカバーする例外クラスを指定しないでください。必要に応じて複数のキャッチを使用し、考えられるすべての例外を処理しようとしないでください。
2. 1 つの try ブロックに大量のコードを入れないようにします。これは良い習慣ではありません。これにより、コードの大部分には例外をスローする可能性のある場所が多すぎるため、プログラムが例外をスローする理由を分析することが困難になります
##この章の概要
例外は PHP5 の新しい重要な機能です、例外メカニズムは、いくつかの非常に重要な利点を提供します。
1. エラー処理をcatch文に集中させることで、エラー処理をアプリケーションの処理から切り離すことができます。これにより、コードが読みやすくなり、見やすくなります。すべての例外をキャッチしてスクリプトの実行を中止するという非常に厳密なポリシーを採用することで、安全で使いやすい例外管理を有効にしながら、必要な回復力をさらに高めることができます。
2. 例外を再スローすると、catch 内のエラー情報が伝播され、例外データ フローが下位層から上位層に渡されます。つまり、例外は、処理方法を決定するのに最適な場所に戻されます。例外を処理します。少し奇妙に思えるかもしれませんが、実際には、例外が発生したときにその処理方法をすぐに決定することができないことがよくあります。
3. 例外メカニズムによって提供されるスロー/キャッチは、エラー識別を直接返すことを回避し、メソッドの戻り値はクラスによって決定できます。他のプログラマーが私たちのコードを使用する場合、面倒な継続的なテストを必要とせずに、希望する形式で i が返されるように指定できるため、エラーの特定と保守が容易になります。