Do You PHP はてブロ

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

独自例外クラスのサブクラスを投げるモジュールのCソース


例外を登録するzend_register_internal_class_ex関数の定義は

ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce, char *parent_name TSRMLS_DC);

となっていて、親クラスを指定する第2引数はzend_class_entry型のポインタなので、独自例外クラスのサブクラスを作りたい場合は単に

zend_class_entry *exception_test_exception_ce;
zend_class_entry *exception_test_sub_exception_ce;
               :
PHP_MINIT_FUNCTION(exception_test)
{
    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);

    INIT_CLASS_ENTRY(ce, "ExceptionTestSubException", NULL);
    exception_test_sub_exception_ce = zend_register_internal_class_ex(&ce, exception_test_exception_ce, NULL TSRMLS_CC);
            :
}

にすれば良いだけなんですね。
先ほどのPEAR::CodeGen_PECLのspecファイルを書き換えると、次のような感じです。

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

 <code position="top">
  <![CDATA[
zend_class_entry *exception_test_exception_ce;
zend_class_entry *exception_test_sub_exception_ce;
  ]]>
 </code>

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

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

  <function name="throwSubException">
   <proto>boolean throwSubException()</proto>
   <code>
    <![CDATA[
zend_throw_exception_ex(exception_test_sub_exception_ce, 0 TSRMLS_CC, "Exception throwd");

RETURN_TRUE;
]]>
   </code>
   <test>
    <code>
     <![CDATA[
try {
    $obj = new ExceptionTest();
    $obj->throwSubException();
    echo 'NG';
} catch (ExceptionTestSubException $e) {
    echo (is_subclass_of($e, 'Exception') ? 'OK' : 'NG');
    echo (is_subclass_of($e, 'ExceptionTestException') ? 'OK' : 'NG');
} catch (ExceptionTestException $e) {
    echo 'NG';
} catch (Exception $e) {
    echo 'NG';
}]]>
    </code>
    <result>OKOK</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);
INIT_CLASS_ENTRY(ce, "ExceptionTestSubException", NULL);
exception_test_sub_exception_ce = zend_register_internal_class_ex(&ce, exception_test_exception_ce, NULL TSRMLS_CC);
]]>
  </code>
 </function>
</extension>