独自例外クラスのサブクラスを投げるモジュールの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>