対象読者
PHPでの基本構文を理解している方で、PHPエクステンションに興味がある方、さらに深くPHPを知りたい方で、C言語の基本的な構文を理解している方を対象としています。
必要な環境
この記事では、PHP 5.4を使用し、Linux環境で確認を行っています。インストール方法は初回を参照してください。
PHPのエラーログにエラー情報を出力する
PHPのエラーは、php.iniで設定しているerror_logに表示されます。以下の表示例はサンプルコードにより表示させた時のエラーログの内容です。
Notice: errchk_report(): simple message in /errchk/errchk.php on line 2 // ・・・(1) Warning: errchk_report(): message format[message arg] in /errchk/errchk.php on line 2 // ・・・(2) Notice: errchk_report(arg1): docref1 message in /errchk/errchk.php on line 2 // ・・・(3) Notice: errchk_report(arg1,arg2): docref2 message in /errchk/errchk.php on line 2 // ・・・(4)
このエラー表示のフォーマットは、以下のようになっています。
[エラーレベル]: [エラーの関数名]: [エラーメッセージ] in [PHPのプログラム名] on line [PHPのプログラムの行数]
エクステンション内で表示させるには、以下の関数を使います。
void php_error_docref0(const char *docref TSRMLS_DC, int type, const char *format, ...) void php_error_docref1(const char *docref TSRMLS_DC, const char *param1, int type, const char *format, ...) void php_error_docref2(const char *docref TSRMLS_DC, const char *param1, const char *param2, int type, const char *format, ...) #define php_error_docref php_error_docref0
php_error_docref0から2まで用意されていますが、実際によく使うと思われるphp_error_docref0だけは数字がつかない別名のphp_error_docrefが定義されており、通常はこちらを利用します。
実際にエクステンション内では、以下のように利用します。
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "simple message"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "message format[%s]", "message arg"); php_error_docref1(NULL TSRMLS_CC, "arg1", E_NOTICE, "docref1 message"); php_error_docref2(NULL TSRMLS_CC, "arg1","arg2", E_USER_NOTICE, "docref2 message");
第一引数に指定するdocrefはPHPのドキュメントへのリンクを表示するためのものですが、PHPのソース内でもあまり使われておらず、NULLを指定すれば問題ありません。
また、指定できるログレベルはPHPのerror_reporing()関数の同様であり、それぞれのエラーレベルはPHPマニュアルのエラー処理での定義済み定数を参照してください。
例外を投げる
エクステンションプログラム内で例外を投げることも可能です。エラーログとは異なり、例外はPHPのプログラムでコントロールすることができますので、より実行時にコントロールしたい場合に利用します。
エクステンション内で例外を投げるには、以下の2つの関数を利用します。
zval * c(zend_class_entry *exception_ce, char *message, long code TSRMLS_DC);
zval * zend_throw_exception_ex(zend_class_entry *exception_ce, long code TSRMLS_DC, char *format, ...);
2つの関数の違いは、エラーメッセージで"%s"などを使ったフォーマット形式が使えるかどうかですが、message変数と、code変数の引数の順番がかわっていますので、注意してください。以下にサンプルコードを示します。
zend_throw_exception(zend_exception_get_default(TSRMLS_C), "exception message", 100 TSRMLS_CC);
zend_class_entryで例外クラスを指定するところで、zend_exception_get_default()関数を使えば、PHPでの標準例外クラスであるExceptionクラスになります。また、zend_class_entryをNULLで指定することも可能ですが、その場合もzend_exception_get_default()と同様になります。
独自の例外を投げる
Exceptionクラスを継承した例外を投げる場合には、zend_class_entryを独自に作成し、それをzend_throw_exception()の引数に設定する必要があります。今までクラスを定義してきましたが、その手順とほとんど変わりません。(1)で独自のzend_class_entryを作成し、(2)で例外の関数を設定します。ただし、Exceptionクラスのメソッドを継承しますので、何も定義はありません。(3)のzend_register_internal_class_exでExceptionクラスを取得するzend_exception_get_default()関数を実行すれば、ErrchkExceptionクラスが定義できます。
zend_class_entry *ce_errchk_exception; // ……(1) // : (省略) static zend_function_entry errchk_exception_methods[] = { // ……(2) {NULL, NULL, NULL} }; // : (省略) PHP_MINIT_FUNCTION(errchk) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "ErrchkException",errchk_exception_methods); ce_errchk_exception = zend_register_internal_class_ex(&ce,zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC); // ……(3) return SUCCESS; }
あとは、通常の例外を投げる時と同様に、以下のようにしてユーザが定義した例外を投げます。
zend_throw_exception_ex(ce_errchk_exception, 100 TSRMLS_CC, "errchk exception");