Do You PHP はてブロ

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

PEAR::CodeGen_PECLの例外定義対応パッチ


PEAR::CodeGen_PECLの構成・動作とCソースでの例外の投げ方が分かってきたので、ここら辺でひとつPEAR::CodeGen_PECLの例外定義対応パッチを作ってみました。

パッチ当てるのが面倒な方は、以下のアーカイブCodeGen_PECLのファイルを上書きしてください。

パッチを適用/ファイルを差し替えると、以下のことが行えるようになります。

  • function要素の属性として「throws」が追加される(関数・メソッドの両者で有効)
  • throws属性にはthrowされる例外クラス名をカンマ区切りで記述
  • 例外クラスに関するクラスエントリなどのコードを出力
  • 関数・メソッドに例外を投げるためのコードを出力
    • code要素の値として独自コードを記載していない場合のみ

たとえば、以下のようなspecファイルの場合、

<?xml version="1.0"?>
<extension name="exception_test" version="0.0.4">

 <function name="TestFunction" throws="TestFunctionException">
  <proto>bool TestFunction()</proto>
 </function>

 <class name="ExceptionTest">
  <function name="throwException" throws="Exception">
   <proto>bool throwException()</proto>
  </function>
  <function name="throwAnotherException" throws="AnotherException">
   <proto>bool throwAnotherException()</proto>
  </function>
  <function name="throwAnotherException2" throws="AnotherException">
   <proto>bool throwAnotherException2()</proto>
  </function>
 </class>

 <class name="ExceptionTest2">
  <function name="throwException" throws="Exception, AnotherException">
   <proto>bool throwException()</proto>
  </function>
  <function name="throwAnotherException" throws="AnotherException">
   <proto>bool throwAnotherException()</proto>
  </function>
 </class>

</extension>

次のようなコードを出力します(長いです)。

/*
   +----------------------------------------------------------------------+
   | unknown license:                                                      |
   +----------------------------------------------------------------------+
   +----------------------------------------------------------------------+
*/

/* $ Id: $ */ 

#include "php_exception_test.h"

#if HAVE_EXCEPTION_TEST

/* {{{ Exception class definitions */
zend_class_entry *AnotherException_exception_ce;
zend_class_entry *TestFunctionException_exception_ce;
/* }}} Exception class definitions*/

/* {{{ Class definitions */

/* {{{ Class ExceptionTest */

static zend_class_entry * ExceptionTest_ce_ptr = NULL;

/* {{{ Methods */


/* {{{ proto bool throwException()
   */
PHP_METHOD(ExceptionTest, throwException)
{
	zend_class_entry * _this_ce;
	zval * _this_zval = NULL;

	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &_this_zval, ExceptionTest_ce_ptr) == FAILURE) {
		return;
	}

	_this_ce = Z_OBJCE_P(_this_zval);

	php_error(E_WARNING, "throwException: not yet implemented"); RETURN_FALSE;

	RETURN_FALSE;
}
/* }}} throwException */



/* {{{ proto bool throwAnotherException()
   */
PHP_METHOD(ExceptionTest, throwAnotherException)
{
	zend_class_entry * _this_ce;
	zval * _this_zval = NULL;

	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &_this_zval, ExceptionTest_ce_ptr) == FAILURE) {
		return;
	}

	_this_ce = Z_OBJCE_P(_this_zval);

	zend_throw_exception_ex(AnotherException_exception_ce, 0 TSRMLS_CC, "AnotherException was threw");

	php_error(E_WARNING, "throwAnotherException: not yet implemented"); RETURN_FALSE;

	RETURN_FALSE;
}
/* }}} throwAnotherException */



/* {{{ proto bool throwAnotherException2()
   */
PHP_METHOD(ExceptionTest, throwAnotherException2)
{
	zend_class_entry * _this_ce;
	zval * _this_zval = NULL;

	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &_this_zval, ExceptionTest_ce_ptr) == FAILURE) {
		return;
	}

	_this_ce = Z_OBJCE_P(_this_zval);

	zend_throw_exception_ex(AnotherException_exception_ce, 0 TSRMLS_CC, "AnotherException was threw");

	php_error(E_WARNING, "throwAnotherException2: not yet implemented"); RETURN_FALSE;

	RETURN_FALSE;
}
/* }}} throwAnotherException2 */


static zend_function_entry ExceptionTest_methods[] = {
	PHP_ME(ExceptionTest, throwException, NULL, /**/ZEND_ACC_PUBLIC)
	PHP_ME(ExceptionTest, throwAnotherException, NULL, /**/ZEND_ACC_PUBLIC)
	PHP_ME(ExceptionTest, throwAnotherException2, NULL, /**/ZEND_ACC_PUBLIC)
	{ NULL, NULL, NULL }
};

/* }}} Methods */

static void class_init_ExceptionTest(void)
{
	zend_class_entry ce;

	INIT_CLASS_ENTRY(ce, "ExceptionTest", ExceptionTest_methods);
	ExceptionTest_ce_ptr = zend_register_internal_class(&ce);
}

/* }}} Class ExceptionTest */

/* {{{ Class ExceptionTest2 */

static zend_class_entry * ExceptionTest2_ce_ptr = NULL;

/* {{{ Methods */


/* {{{ proto bool throwException()
   */
PHP_METHOD(ExceptionTest2, throwException)
{
	zend_class_entry * _this_ce;
	zval * _this_zval = NULL;

	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &_this_zval, ExceptionTest2_ce_ptr) == FAILURE) {
		return;
	}

	_this_ce = Z_OBJCE_P(_this_zval);

	zend_throw_exception_ex(AnotherException_exception_ce, 0 TSRMLS_CC, "AnotherException was threw");

	php_error(E_WARNING, "throwException: not yet implemented"); RETURN_FALSE;

	RETURN_FALSE;
}
/* }}} throwException */



/* {{{ proto bool throwAnotherException()
   */
PHP_METHOD(ExceptionTest2, throwAnotherException)
{
	zend_class_entry * _this_ce;
	zval * _this_zval = NULL;

	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &_this_zval, ExceptionTest2_ce_ptr) == FAILURE) {
		return;
	}

	_this_ce = Z_OBJCE_P(_this_zval);

	zend_throw_exception_ex(AnotherException_exception_ce, 0 TSRMLS_CC, "AnotherException was threw");

	php_error(E_WARNING, "throwAnotherException: not yet implemented"); RETURN_FALSE;

	RETURN_FALSE;
}
/* }}} throwAnotherException */


static zend_function_entry ExceptionTest2_methods[] = {
	PHP_ME(ExceptionTest2, throwException, NULL, /**/ZEND_ACC_PUBLIC)
	PHP_ME(ExceptionTest2, throwAnotherException, NULL, /**/ZEND_ACC_PUBLIC)
	{ NULL, NULL, NULL }
};

/* }}} Methods */

static void class_init_ExceptionTest2(void)
{
	zend_class_entry ce;

	INIT_CLASS_ENTRY(ce, "ExceptionTest2", ExceptionTest2_methods);
	ExceptionTest2_ce_ptr = zend_register_internal_class(&ce);
}

/* }}} Class ExceptionTest2 */

/* }}} Class definitions*/

/* {{{ exception_test_functions[] */
function_entry exception_test_functions[] = {
	PHP_FE(TestFunction        , NULL)
	{ NULL, NULL, NULL }
};
/* }}} */


/* {{{ exception_test_module_entry
 */
zend_module_entry exception_test_module_entry = {
	STANDARD_MODULE_HEADER,
	"exception_test",
	exception_test_functions,
	PHP_MINIT(exception_test),     /* Replace with NULL if there is nothing to do at php startup   */
	PHP_MSHUTDOWN(exception_test), /* Replace with NULL if there is nothing to do at php shutdown  */
	PHP_RINIT(exception_test),     /* Replace with NULL if there is nothing to do at request start */
	PHP_RSHUTDOWN(exception_test), /* Replace with NULL if there is nothing to do at request end   */
	PHP_MINFO(exception_test),
	"0.0.1",
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_EXCEPTION_TEST
ZEND_GET_MODULE(exception_test)
#endif


/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(exception_test)
{
	class_init_ExceptionTest();
	class_init_ExceptionTest2();
	zend_class_entry ce;
	INIT_CLASS_ENTRY(ce, "AnotherException", NULL);
	AnotherException_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
	INIT_CLASS_ENTRY(ce, "TestFunctionException", NULL);
	TestFunctionException_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);

	/* add your stuff here */

	return SUCCESS;
}
/* }}} */


/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(exception_test)
{

	/* add your stuff here */

	return SUCCESS;
}
/* }}} */


/* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(exception_test)
{
	/* add your stuff here */

	return SUCCESS;
}
/* }}} */


/* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(exception_test)
{
	/* add your stuff here */

	return SUCCESS;
}
/* }}} */


/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(exception_test)
{
	php_info_print_box_start(0);
	php_printf("<p>The unknown extension</p>\n");
	php_printf("<p>Version 0.0.1devel (2007-04-05)</p>\n");
	php_info_print_box_end();
	/* add your stuff here */

}
/* }}} */


/* {{{ proto bool TestFunction()
   */
PHP_FUNCTION(TestFunction)
{
	if (ZEND_NUM_ARGS()>0)  {
		WRONG_PARAM_COUNT;
	}

	zend_throw_exception_ex(TestFunctionException_exception_ce, 0 TSRMLS_CC, "TestFunctionException was threw");

	php_error(E_WARNING, "TestFunction: not yet implemented"); RETURN_FALSE;

	RETURN_FALSE;
}
/* }}} TestFunction */

#endif /* HAVE_EXCEPTION_TEST */


/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */