開発畑トップ   »  PHP   »  今日からプログラマー!PHP入門【テンプレートエンジン作成編】   »  今日からプログラマー!PHP入門(第7回)

今日からプログラマー!PHP入門(第7回)

今日から5月ですね。だんだんと温かく・・・というか暑くなってきてます。春はどこに行ったんだろう。

あ、そうそう。このブログのシステムでもあるBlogn3アルファ版を公式サイトでリリース致しました。
興味のある方は一度使ってみてくださいませ~【宣伝】

さて、今回も始めましょう。今プロPHP第7回です。
今回はユーザー定義のエラーハンドラー作成です。


エラーハンドラー

と、その前に前回のおさらいです。

前回はエラーの種類やevalの挙動について学びました。
簡単に説明すると、NoticeエラーとWarningエラーは処理が止まらない。またevalで実行した場合はParseエラーでも止まらないということです。
evalを使った場合のFatalエラーはご自分で試してみてください(^-^)

では、さっそくコードを作ってみましょう
今回はPHP公式サイトのドキュメントからコードを引用します。(公式サイトに書かれているコードはすごく為になるので、時間のある時にでもちょくちょく読むといいと思いますよー)

<?php
// エラーハンドラ関数
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
	if (!(error_reporting() & $errno)) {
		// error_reporting 設定に含まれていないエラーコードです
		return;
	}
	switch ($errno) {
		case E_USER_ERROR:
			echo "<b>My ERROR</b> [$errno] $errstr<br />\n";
			echo "  Fatal error on line $errline in file $errfile";
			echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
			echo "Aborting...<br />\n";
			exit(1);
			break;
		case E_USER_WARNING:
			echo "<b>My WARNING</b> [$errno] $errstr<br />\n";
			break;
		case E_USER_NOTICE:
			echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";
			break;
		default:
			echo "Unknown error type: [$errno] $errstr<br />\n";
			break;
	}
	/* PHP の内部エラーハンドラを実行しません */
	return true;
}

// エラー処理のテスト用関数
function scale_by_log($vect, $scale)
{
	if (!is_numeric($scale) || $scale <= 0) {
		trigger_error("log(x) for x <= 0 is undefined, you used: scale = $scale", E_USER_ERROR);
	}
	if (!is_array($vect)) {
		trigger_error("Incorrect input vector, array of values expected", E_USER_WARNING);
		return null;
	}
	$temp = array();
	foreach($vect as $pos => $value) {
		if (!is_numeric($value)) {
			trigger_error("Value at position $pos is not a number, using 0 (zero)", E_USER_NOTICE);
			$value = 0;
		}
		$temp[$pos] = log($scale) * $value;
	}
	return $temp;
}
// 定義したエラーハンドラを設定する
$old_error_handler = set_error_handler("myErrorHandler");

// エラーを発生します。まず、数値でない項目が混ざった配列を定義します。
echo "vector a\n";
$a = array(2, 3, "foo", 5.5, 43.3, 21.11);
print_r($a);
// 二番目の配列を生成します。
echo "----\nvector b - a notice (b = log(PI) * a)\n";
/* Value at position $pos is not a number, using 0 (zero) */
$b = scale_by_log($a, M_PI);
print_r($b);
// 配列の代わりに文字列を渡しており、問題を発生します。
echo "----\nvector c - a warning\n";
/* Incorrect input vector, array of values expected */
$c = scale_by_log("not array", 2.3);
var_dump($c); // NULL
// ゼロまたは負数の対数が定義されないという致命的なエラーを発生します。
echo "----\nvector d - fatal error\n";
/* log(x) for x <= 0 is undefined, you used: scale = $scale" */
$d = scale_by_log($a, -2.5);
var_dump($d); // ここには到達しません
?>

では、順を追ってコードを見てみましょう
まずは、エラー処理用のユーザー定義関数です。

エラーハンドラ関数

  • 1行目はPHPの開始タグですね。
    2行目はコメント行です。
    コメントには3通りの指定方法がありますが、実際に使うのは2通りですね。(♯はあまり使われていません)
  • 3行目
    ユーザー関数myErrorHanderを作成します。
    この関数は後で出てくるset_error_handler関数から呼び出されることが前提になっているので、引数が定められています。
  • 5行目
    error_reporting関数は引数を指定すれば、その設定したエラーがけ出力し、引数を入れなければ、現在のエラー出力の情報を返します
    戻り値は数値なので(0だとエラー表示なし)、5行目のif文は「(error_reportingの戻り値と$errno変数の値が0の場合」という条件になります。
  • 7行目
    5行目で「エラーが無い場合」という条件なので、returnで処理を終了しています。
  • 9行目
    switch文はif文に似た比較処理です。
    異なる点は、switch文は1つの変数に対して色々な比較を行うという点です。
    今回は$errno変数の値についての比較になります。
  • 10行目
    E_USER_ERRORは第5回で出てきた定義済み定数です。
    リンク先をみるとE_USER_ERROR定数の値は256になっています。
    なので、ここでは$errno変数の値が256だった場合の処理になります。
  • 11行目~14行目
    では、$errno変数の値が256だった場合の処理内容です。
    echo文でエラーを表示しています。
    ここでも定数が出てきました。PHP_VERSIONとPHP_OSです。
    これらも定義済み定数です。(先ほどの定義済み定数とリンク先後異なりますのでご注意下さい。)
  • 15行目
    exitで終了しています。
    exitに引数「1」が入っています。exitは引数に文字列がある場合は文字列を出力して終了しますが、引数が数値(0~254まで)の場合は、終了ステータスとして使用されます。
  • 16行目
    break文は、現在実行中の構造言語を中断して抜けだす処理です。
    この場合はswitch文を終了して、27行目に進みます。
  • 17行目
    次は$errno変数がE_USER_WARNING(512)だった場合の処理です
  • 18行目
    echo文でエラーを表示するだけで、処理の終了(exit)はしていません。
    なぜなら、前回習ったようにNoticeとWarningはエラーを出した後も処理を継続するからです。
  • 19行目
    break文でswitch文の処理を抜け出します。
    もし、ここでbreak文が無い場合は次のE_USER_NOTICEの処理にまで進んでしまいます。
  • 20行目~22行目
    E_USER_NOTICE(1024)の場合の処理です。
  • 23行目~25行目
    defaultは、「それ以外」の処理です。
    switch文のcaseで指定した結果以外の場合はここで処理されます。
  • 28行目
    これでユーザー定義のエラー関数は終了です。
    return trueで結果を返しています。

エラー処理のテスト用関数

次はワザとエラーを発生させるための処理関数です。

  • 31行目
    ユーザー定義関数scale_by_log関数を作成します。
  • 33行目~35行目
    E_USER_ERRORを発生させるための処理です。
    is_numeric関数は数値かどうかを判別する関数です。
    この場合の数値というのは10進数以外にも適応されますのでご注意ください(8進数や16進数も数値とみなします)
    trigger_errorはエラーをさっせいさせる関数です。
  • 36行目~39行目
    E_USER_WARNINGを発生させるための処理です。
    is_array関数は配列かどうかを判別する関数です。
  • 40行目~48行目
    foreach文でE_USER_NOTICEかどうかを調べています。

ここまででエラー発生用の関数が終了です。
次はエラーハンドラーの設定と、実際にエラーを発生させる処理です。

エラー発生用の処理

  • 51行目
    set_error_handler関数で先ほど作成したユーザー定義関数myErrorHandlerを設定します。
  • 53行目~
    ここからは、実際にエラーを発生させる処理になります。
    53行目のechoで”(ダブルクォート)内にある¥nは改行コードです。
    また、print_r関数は変数や配列の値を表示します。(echoは配列を表示できないので、print_rを配列の表示の場合はprint_r関数を使います)
    65行目のvar_dump関数はprint_r関数と同じように変数の値を表示します。

実行結果については、PHP公式サイトのドキュメントに載っていますので、そちらも参考ししてください。
このように、エラーが発生した場合も想定してプログラミングをしていく事はとても重要です。
(なぜなら、使用者は開発者の思いもよらないことをするものですからw)

上記のエラーハンドラ関数は、エラーが出た場合にエラーを表示するだけの簡単なものですが、ちょっと改良するだけでエラー内容をファイルに保存することも可能です。
大きなブログラムの場合などは、複数のエラーが発生してもファイルにエラー内容を保存することで、追跡解析して不具合修正を楽にすることができたりするのです。

今回はここまでです。
次回はテンプレートエンジンの開発に戻りますよ。次はテンプレートファイル内にPHPコードが入らないようにする処理をやってみます。
では、また来週~

コメントをどうぞ!