PHPエクステンションのエラー処理

CodeZine / 2014年4月4日 14時0分

 本連載では、PHPエクステンションの作成方法を紹介します。前回までで基本的な関数からクラス定義、そしてストリーム処理の開発方法について紹介しました。今回はそこで紹介ができなかったエラー処理に対する方法と、より開発しやすいように筆者が利用しているCMakeビルドシステムについて紹介します。

■対象読者

 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クラスが定義できます。

独自例外クラス(errchk.cの抜粋)
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");


CodeZine

トピックスRSS

ランキング