Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

例外を投げるモジュールのCソース


PHP5から例外が使えますが、「例外を投げるモジュール」のCソースはどうなってるのか、ちょっと調べてみました。
結論を先に言うと、以下の2つを書くことになるようです。

  • 例外クラス用ポインタの定義(zend_class_entry型のポインタ)
  • PHP_MINIT_FUNCTION(モジュール単位の初期化関数)内で例外クラスの初期化(INIT_CLASS_ENTRYマクロ)と登録(zend_register_internal_class/zend_register_internal_class_ex)

PEAR::CodeGen_PECLのspecファイルで書くと以下のような感じです。ExceptionTestクラスのthrowExceptionメソッドを呼び出すと、例外ExceptionTestExceptionを投げてきます。

<?xml version="1.0"?>
<extension name="exception_test" version="0.0.1">
 <summary>from exception_test</summary>
 <description>from exception_test</description>
 <license>PHP</license>

 <class name="ExceptionTest">
  <function name="throwException">
   <proto>boolean throwException()</proto>
   <code>
    <![CDATA[
zend_throw_exception_ex(exception_test_exception_ce, 0 TSRMLS_CC, "Exception threw");

RETURN_TRUE;
]]>
   </code>
   <test>
    <code>
     <![CDATA[
try {
    $obj = new ExceptionTest();
    $obj->throwException();
    echo 'NG';
} catch (Exception $e) {
    echo 'OK';
}]]>
    </code>
    <result>OK</result>
   </test>
  </function>
 </class>

 <function role="internal" name="MINIT">
  <code>
<![CDATA[
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "ExceptionTestException", NULL);
exception_test_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
]]>
  </code>
 </function>
</extension>

このExceptionTestExceptionクラス、PHP組み込みのExceptionクラスのサブクラスになっています。確認のためにZend/zend_exceptions.c(PHP5.2.1)を見てみると、以下のようになっていました。

zend_class_entry *default_exception_ce;
                          :
ZEND_API zend_class_entry *zend_exception_get_default(TSRMLS_D) /* {{{ */
{
    return default_exception_ce;
}
                          :
void zend_register_default_exception(TSRMLS_D) /* {{{ */
{
    zend_class_entry ce;

    INIT_CLASS_ENTRY(ce, "Exception", default_exception_functions);
    default_exception_ce = zend_register_internal_class(&ce TSRMLS_CC);
                          :
}

Exceptionクラスは基底クラスなのでzend_register_internal_classを使っていますが、ほぼ同じような手順で登録されているのが分かります。