概要
状態:-
閲覧数:3,845
投稿日:2014-03-03
更新日:2014-03-19
ユーザー定義のエラーハンドラ関数を設定する標準関数
・「実行時のエラー処理をユーザが定義する」ために、「ユーザ定義のエラーハンドラ関数」を設定
構文
また、以下のエラータイプは、ユーザ定義の関数では扱えない。 E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING および set_error_handler() がコールされたファイルで発生した 大半の E_STRICT。つまり、Fatal Error は処理できない(ちなみに同じFatal Error でも、例外が投げられる時もあれば、投げられないときもある)
仕組
・エラーイベントを処理する「エラーハンドラ」(デフォルトのエラーハンドラはエラーメッセージを表示)を、「ユーザー定義エラーハンドラ」に置き換える
メリット
・PHPスクリプトでエラーハンドラを記述できるため、特定のエラー発生時に管理者にメールを送信を行うなどの必要なエラー処理を行うことができる
特徴
・set_error_handler が呼び出された後、エラーが発生した場合、set_error_handler で登録した関数でエラー処理が行われる
・一度set_error_handler が呼び出されると restore_error_handler を使ってエラー処理を解除するまで、エラーを捕捉し続ける
・例外をスローするのは、set_error_handler()で指定した関数内1箇所のみ
処理の流れ
・1.tryブロック内の処理でエラー発生
・2.発生したエラーは、「set_error_handler()の引数で指定した関数」で処理
・3.同関数内より、例外をスロー(スロー記述は、この一箇所だけ)
・「実行時のエラー処理をユーザが定義する」ために、「ユーザ定義のエラーハンドラ関数」を設定
構文
mixed set_error_handler ( callback $error_handler [, int $error_types = E_ALL | E_STRICT ] )
set_error_handler( エラー処理関数 [, エラータイプ ])
・第 1 引数 … スクリプトのエラー処理を行うユーザ関数 (error_handler)を指定
・第 2 引数 … エラー出力レベルを指定(エラー処理関数の起動制御に使用)。なお、エラータイプを指定しない場合は、エラー処理関数が全てのエラーで起動
※エラー処理関数が FALSE を返さない限り、この引数 で指定した型のエラーでは PHP 標準のエラーハンドラは起動しないので注意が必要
・第 1 引数 … スクリプトのエラー処理を行うユーザ関数 (error_handler)を指定
・第 2 引数 … エラー出力レベルを指定(エラー処理関数の起動制御に使用)。なお、エラータイプを指定しない場合は、エラー処理関数が全てのエラーで起動
※エラー処理関数が FALSE を返さない限り、この引数 で指定した型のエラーでは PHP 標準のエラーハンドラは起動しないので注意が必要
エラー処理関数 ( エラーレベル , 発生したエラーメッセージ[, エラーが発生したPHPスクリプト名[, エラーが発生した行番号 [, エラーが発生したスコープ内での全ての変数を格納した配列]]] )
・第 1 引数 … 発生させる エラーの出力レベルを整数(ビット値)で格納
・第 2 引数 … 発生したエラーメッセージを文字列で格納
・第 3 引数 … オプション/エラーが発生したファイルの名前を文字列で格納
・第 4 引数 … オプション/エラーが発生した行番号を整数で格納
・第 5 引数 … オプション/エラーが発生したスコープ内でのすべての変数を格納した 配列。 ユーザエラーハンドラは、この引数を書き換えては いけない
※error_reporting() の設定にかかわらず、どのような場合でもユーザが設定したエラー処理関数(エラーハンドラ)がコールされる。但し、この場合でも エラー処理関数(エラーハンドラ)で error_reporting() のカレントの値を読み込み、それに合わせ適切に動作させることは可能。なお、エラーを発生した命令の前に @ エラー制御演算子 が付加されている場合、この値は 0 となる。・第 1 引数 … 発生させる エラーの出力レベルを整数(ビット値)で格納
・第 2 引数 … 発生したエラーメッセージを文字列で格納
・第 3 引数 … オプション/エラーが発生したファイルの名前を文字列で格納
・第 4 引数 … オプション/エラーが発生した行番号を整数で格納
・第 5 引数 … オプション/エラーが発生したスコープ内でのすべての変数を格納した 配列。 ユーザエラーハンドラは、この引数を書き換えては いけない
また、以下のエラータイプは、ユーザ定義の関数では扱えない。 E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING および set_error_handler() がコールされたファイルで発生した 大半の E_STRICT。つまり、Fatal Error は処理できない(ちなみに同じFatal Error でも、例外が投げられる時もあれば、投げられないときもある)
詳細
仕組
・エラーイベントを処理する「エラーハンドラ」(デフォルトのエラーハンドラはエラーメッセージを表示)を、「ユーザー定義エラーハンドラ」に置き換える
メリット
・PHPスクリプトでエラーハンドラを記述できるため、特定のエラー発生時に管理者にメールを送信を行うなどの必要なエラー処理を行うことができる
特徴
・set_error_handler が呼び出された後、エラーが発生した場合、set_error_handler で登録した関数でエラー処理が行われる
・一度set_error_handler が呼び出されると restore_error_handler を使ってエラー処理を解除するまで、エラーを捕捉し続ける
・例外をスローするのは、set_error_handler()で指定した関数内1箇所のみ
処理の流れ
・1.tryブロック内の処理でエラー発生
・2.発生したエラーは、「set_error_handler()の引数で指定した関数」で処理
・3.同関数内より、例外をスロー(スロー記述は、この一箇所だけ)
「try~catch」「set_error_handler」を組み合わせるメリット
try~catchだけ
何度もスロー記述をしなければいけない
public function hoge() {
try {
if (TRUE === $error) {
throw new Exception($e);
}
if (~~~) {
throw new Exception($e);
}
} catch(Exception $e) {
}
}
set_error_handler()も利用
スロー記述は一箇所だけ
public static function my_error_handler($errno,$errstr,$errfile,$errline) {
throw new Exception($errst,($errno);
}
public function hoge() {
set_error_handler("クラス名::my_error_handler");
try {
} catch(Exception $e) {
}
restore_error_handler();
}
static
set_error_handler() は staticで書いておけば、下記何れでも利用可
・set_error_handler("クラス名::my_error_handler");
・set_error_handler("self::my_error_handler");
・set_error_handler(array($this,'my_error_handler'));
コード例
tryブロックの外
try~catch未利用
・set_exception_handler関数を利用(Exceptionクラスは利用しているものの、try~catchは利用せず、例外を明示的に投げているだけ)
・set_exception_handler関数では、例外が捕捉されなかった場合のデフォルトの例外ハンドラを指定することができる
・下記の例では、tryブロックの外で例外を投げているため、通常はFatal errorとなるが、set_exception_handler()で例外ハンドラを指定しているため、exceptionHandler関数が呼ばれている
・注意すべき点として、例外ハンドラの処理後にPHPプログラムは実行を終了してしまう
function exceptionHandler($e)
{
echo $e->getMessage(), PHP_EOL;
}
set_exception_handler('exceptionHandler');
throw new Exception('catchされなかった例外');
echo 'end', PHP_EOL;
// 出力:catchされなかった例外
・結果
catchされなかった例外
ファイルオープン
Warning:エラー(ファイルオープンエラー)のエラーハンドリング
function test_error_handler($errorno,$errstr,$errfile,$errline,$errcontext) {
switch ($errno) {
case E_ERROR://ユーザ定義関数では、E_ERRORは扱えない
echo "致命的エラー:" . $errorno . " ユーザー作成エラーメッセージ:" . $errstr. " エラー発生行数:" . $errline."<br />";
break;
default:
echo "その他のエラー エラーコード:" . $errorno . "<br> ユーザー作成エラーメッセージ:" . $errstr . "<br> エラー発生行数:" . $errline."<br>";
break;
}
}
set_error_handler("test_error_handler");
$fd = fopen("c:/temp/azz.txt","r");
・結果
その他のエラー エラーコード:2
ユーザー作成エラーメッセージ:fopen(c:/temp/azz.txt): failed to open stream: No such file or directory
エラー発生行数:34
ユーザー作成エラーメッセージ:fopen(c:/temp/azz.txt): failed to open stream: No such file or directory
エラー発生行数:34
0除算
Warning:エラー(0 除算)のエラーハンドリング
・エラータイプにE_ALL引数を指定
function my_error_handler ( $errno, $errstr, $errfile, $errline, $errcontext ) {
echo "[$errno] $errstr ($errline)行目\n";
}
set_error_handler( 'my_error_handler', E_ALL );
$i = 5/0;
・結果
[2] Division by zero (29)行目
try~catch利用
・set_error_handler()の引数で指定したメソッドで、Exceptionを継承した例外クラスのインスタンスオブジェクトをスロー
・1.tryブロック内の処理でエラー発生
・2.発生したエラーは、「set_error_handler()の引数で指定したメソッド」で処理
・3.同メソッドより、「Exceptionを継承した例外クラスのインスタンスオブジェクト」をスロー
・4.例外キャッチ
function errorHandler($errno, $errstr, $errfile, $errline) {
throw new Exception($errstr, $errno);//3.例外をスロー
}
set_error_handler('errorHandler');//2.エラーを「引数で指定した関数」で処理
try {
5/0;//1.… 0除算。Warningエラー発生
} catch (Exception $e) {//4.例外をキャッチ
echo $e->getMessage();
}
・処理結果
Division by zero
・set_error_handler()は、Warning:エラー(0 除算)をエラーハンドリング出来るが、Fatal error: エラー(未定義関数呼び出し/致命的かつ復帰できない場合)は、エラーハンドリング出来ない。これは Fatal error (致命的エラー) の箇所で、スクリプトが終了処理してしまい、ユーザー定義のエラーハンドラ関数が呼び出されないため
function my_error_handler ( $errno, $errstr, $errfile, $errline, $errcontext ) {
// echo "[$errno] $errstr $errfile($errline)\n";
echo "[$errno] $errstr ($errline)\n";
}
//set_error_handlerがない状態
$i = 5/0;//0 除算でエラー発生→Warning:
//foo();//未定義関数でエラー発生→Fatal error:ここで処理終了するため、コメントアウト
set_error_handler( 'my_error_handler', E_ALL );
$i = 5/0;//0 除算でエラー発生→Warning:
foo();//未定義関数でエラー発生→Fatal error:ここで処理終了
上記のようなエラーハンドラ関数で処理できないエラーについては、スクリプトのシャットダウン関数を利用して処理。シャットダウン関数は register_shutdown_function 関数で指定
クラス
echo 'phpversion : ' . phpversion() . "\n<br>";
//
// PHPエラーを例外(Exception)へ変換
//
class MyException extends Exception
{
public function __construct($errno, $errstr, $errfile, $errline)
{
p($errno ); //8…エラー出力レベル(ビット値)
p($errstr ); //Undefined variable: xxx
//p($errfile ); //エラーファイル
p($errline ); //エラー行数
// エラー定数(エラー出力レベル/ビット値)と文字列のマッピング(連想配列)
$errlev = array(
E_USER_ERROR => 'FATAL',
E_ERROR => 'FATAL',
E_USER_WARNING => 'WARNING',
E_WARNING => 'WARNING',
E_USER_NOTICE => 'NOTICE',
E_NOTICE => 'NOTICE',
E_STRICT => 'E_STRICT'
);
p($errlev );
/*出力
Array
(
[256] => FATAL
[1] => FATAL
[512] => WARNING
[2] => WARNING
[1024] => NOTICE
[8] => NOTICE
[2048] => E_STRICT
)
*/
$add_msg= (string)$errno;//8
p($errlev[$errno]);//NOTICE…取得した「ビット値」を、用意した連想配列のキーへ対応させ、値を取得
if (isset($errlev[$errno])) {
$add_msg = $errlev[$errno] . ' : ';
}
parent::__construct($add_msg . $errstr, $errno);//(エラー定数+)エラーメッセージ,例外コード
$this->file = $errfile;//プロパティへのセッター
$this->line = $errline;//プロパティへのセッター
}
}
function errorHandler($errno, $errstr, $errfile, $errline)
{
throw new MyException($errno, $errstr, $errfile, $errline);
}
set_error_handler('errorHandler');
//
// 以下テストコード
//
error_reporting(E_ALL|E_STRICT);//E_ALL+E_STRICT
function funcA()
{
echo $xxx; // 意図的に、未定義の変数を参照しNOTICEを発生させる
}
try {
funcA();
}
catch (Exception $e) {
echo "--------------\n<br><pre>";
echo $e . "</pre>\n<br>";
echo "--------------\n<br>";
}
/*出力
phpversion : 5.3.8
8
Undefined variable: xxx
85
Array
(
[256] => FATAL
[1] => FATAL
[512] => WARNING
[2] => WARNING
[1024] => NOTICE
[8] => NOTICE
[2048] => E_STRICT
)
NOTICE
--------------
exception 'MyException' with message 'NOTICE : Undefined variable: xxx' in /○○/exception/13.php:85
Stack trace:
#0 /○○/exception/13.php(85): errorHandler(8, 'Undefined varia...', '/○○/ibj/pu...', 85, Array)
#1 /○○/exception/13.php(89): funcA()
#2 {main}
*/