mirror of https://github.com/swig/swig
Make PHP directors work more like other languages
A PHP exception now gets translated to a C++ exception to skips over C++ code to get back to PHP, avoiding the need to gate every directorout typemap on EG(exception).
This commit is contained in:
parent
10d87100ea
commit
50426aae20
|
@ -1159,13 +1159,32 @@ should suffice in most cases:
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
%feature("director:except") {
|
%feature("director:except") {
|
||||||
if ($error == FAILURE) {
|
#if SWIG_VERSION >= 0x040100
|
||||||
|
if ($error != NULL)
|
||||||
|
#else
|
||||||
|
if ($error == FAILURE)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
throw Swig::DirectorMethodException();
|
throw Swig::DirectorMethodException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you only need to support SWIG >= 4.1.0, you can just use the
|
||||||
|
<tt>($error != NULL)</tt> condition.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In SWIG 4.1.0, <tt>$error</tt> was changed in the SWIG/PHP director
|
||||||
|
implementation to make it work more like how it does for other languages.
|
||||||
|
Previously, <tt>$error</tt> didn't actually indicate an exception, but instead
|
||||||
|
was only set to <tt>FAILURE</tt> if there was a problem calling the PHP method.
|
||||||
|
Now <tt>$error</tt> indicates if the PHP method threw a PHP exception, and
|
||||||
|
directorout typemaps for PHP no longer need to be gated by <tt>if (EG(exception))</tt>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This code will check the PHP error state after each method call from a
|
This code will check the PHP error state after each method call from a
|
||||||
director into PHP, and throw a C++ exception if an error occurred. This
|
director into PHP, and throw a C++ exception if an error occurred. This
|
||||||
|
|
|
@ -18,22 +18,7 @@ namespace Swig {
|
||||||
|
|
||||||
%include "std_string.i"
|
%include "std_string.i"
|
||||||
|
|
||||||
#ifdef SWIGPHP
|
#if defined SWIGPHP || defined SWIGPYTHON
|
||||||
|
|
||||||
%feature("director:except") {
|
|
||||||
if ($error == FAILURE) {
|
|
||||||
Swig::DirectorMethodException::raise("$symname");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
%exception {
|
|
||||||
try { $action }
|
|
||||||
catch (Swig::DirectorException &) { SWIG_fail; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SWIGPYTHON
|
|
||||||
|
|
||||||
%feature("director:except") {
|
%feature("director:except") {
|
||||||
if ($error != NULL) {
|
if ($error != NULL) {
|
||||||
|
|
|
@ -17,11 +17,7 @@
|
||||||
%feature("director") Foo;
|
%feature("director") Foo;
|
||||||
|
|
||||||
%feature("director:except") {
|
%feature("director:except") {
|
||||||
#ifndef SWIGPHP
|
|
||||||
if ($error != NULL) {
|
if ($error != NULL) {
|
||||||
#else
|
|
||||||
if ($error == FAILURE) {
|
|
||||||
#endif
|
|
||||||
throw Swig::DirectorMethodException();
|
throw Swig::DirectorMethodException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,18 +93,15 @@
|
||||||
|
|
||||||
%typemap(directorout) SWIGTYPE ($&1_ltype tmp)
|
%typemap(directorout) SWIGTYPE ($&1_ltype tmp)
|
||||||
%{
|
%{
|
||||||
/* If exit was via exception, PHP NULL is returned so skip the conversion. */
|
if ($needNewFlow) {
|
||||||
if (!EG(exception)) {
|
tmp = ($&1_ltype) &SWIG_Z_FETCH_OBJ_P($1)->ptr;
|
||||||
if ($needNewFlow) {
|
SWIG_Z_FETCH_OBJ_P($1)->newobject = 0;
|
||||||
tmp = ($&1_ltype) &SWIG_Z_FETCH_OBJ_P($1)->ptr;
|
} else {
|
||||||
SWIG_Z_FETCH_OBJ_P($1)->newobject = 0;
|
if (SWIG_ConvertPtr($input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) {
|
||||||
} else {
|
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $&1_descriptor");
|
||||||
if (SWIG_ConvertPtr($input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) {
|
|
||||||
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $&1_descriptor");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$result = *tmp;
|
|
||||||
}
|
}
|
||||||
|
$result = *tmp;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%typemap(in) SWIGTYPE *,
|
%typemap(in) SWIGTYPE *,
|
||||||
|
|
|
@ -55,6 +55,9 @@ static zend_always_inline void *zend_object_alloc(size_t obj_size, zend_class_en
|
||||||
|
|
||||||
#define SWIG_fail goto fail
|
#define SWIG_fail goto fail
|
||||||
|
|
||||||
|
// If there's an active PHP exception, just return so it can propagate.
|
||||||
|
#define SWIG_FAIL() do { if (!EG(exception)) zend_error_noreturn(SWIG_ErrorCode(), "%s", SWIG_ErrorMsg()); goto thrown; } while (0)
|
||||||
|
|
||||||
static const char *default_error_msg = "Unknown error occurred";
|
static const char *default_error_msg = "Unknown error occurred";
|
||||||
static int default_error_code = E_ERROR;
|
static int default_error_code = E_ERROR;
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,8 @@ namespace std {
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%typemap(directorout) string %{
|
%typemap(directorout) string %{
|
||||||
if (!EG(exception)) {
|
|
||||||
convert_to_string($input);
|
convert_to_string($input);
|
||||||
$result.assign(Z_STRVAL_P($input), Z_STRLEN_P($input));
|
$result.assign(Z_STRVAL_P($input), Z_STRLEN_P($input));
|
||||||
}
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%typemap(out) string %{
|
%typemap(out) string %{
|
||||||
|
@ -74,12 +72,10 @@ namespace std {
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%typemap(directorout) string & ($*1_ltype *temp) %{
|
%typemap(directorout) string & ($*1_ltype *temp) %{
|
||||||
if (!EG(exception)) {
|
|
||||||
convert_to_string($input);
|
convert_to_string($input);
|
||||||
temp = new $*1_ltype(Z_STRVAL_P($input), Z_STRLEN_P($input));
|
temp = new $*1_ltype(Z_STRVAL_P($input), Z_STRLEN_P($input));
|
||||||
swig_acquire_ownership(temp);
|
swig_acquire_ownership(temp);
|
||||||
$result = temp;
|
$result = temp;
|
||||||
}
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%typemap(argout) string & %{
|
%typemap(argout) string & %{
|
||||||
|
|
|
@ -75,19 +75,15 @@
|
||||||
%}
|
%}
|
||||||
%typemap(directorout) TYPE
|
%typemap(directorout) TYPE
|
||||||
%{
|
%{
|
||||||
if (!EG(exception)) {
|
CONVERT_IN($result, $1_ltype, *$input);
|
||||||
CONVERT_IN($result, $1_ltype, *$input);
|
|
||||||
}
|
|
||||||
%}
|
%}
|
||||||
%typemap(directorout) const TYPE &
|
%typemap(directorout) const TYPE &
|
||||||
%{
|
%{
|
||||||
$*1_ltype swig_val;
|
$*1_ltype swig_val;
|
||||||
if (!EG(exception)) {
|
CONVERT_IN(swig_val, $*1_ltype, *$input);
|
||||||
CONVERT_IN(swig_val, $*1_ltype, *$input);
|
$1_ltype temp = new $*1_ltype(($*1_ltype)swig_val);
|
||||||
$1_ltype temp = new $*1_ltype(($*1_ltype)swig_val);
|
swig_acquire_ownership(temp);
|
||||||
swig_acquire_ownership(temp);
|
$result = temp;
|
||||||
$result = temp;
|
|
||||||
}
|
|
||||||
%}
|
%}
|
||||||
%typemap(directorfree) const TYPE &
|
%typemap(directorfree) const TYPE &
|
||||||
%{
|
%{
|
||||||
|
|
|
@ -400,20 +400,6 @@ public:
|
||||||
Printf(s_header, "#define SWIG_ErrorMsg() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_msg)\n", module);
|
Printf(s_header, "#define SWIG_ErrorMsg() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_msg)\n", module);
|
||||||
Printf(s_header, "#define SWIG_ErrorCode() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_code)\n", module);
|
Printf(s_header, "#define SWIG_ErrorCode() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_code)\n", module);
|
||||||
|
|
||||||
/* The following can't go in Lib/php/phprun.swg as it uses SWIG_ErrorMsg(), etc
|
|
||||||
* which has to be dynamically generated as it depends on the module name.
|
|
||||||
*/
|
|
||||||
Append(s_header, "#ifdef __GNUC__\n");
|
|
||||||
Append(s_header, "static void SWIG_FAIL(void) __attribute__ ((__noreturn__));\n");
|
|
||||||
Append(s_header, "#endif\n\n");
|
|
||||||
Append(s_header, "static void SWIG_FAIL(void) {\n");
|
|
||||||
Append(s_header, " zend_error(SWIG_ErrorCode(), \"%s\", SWIG_ErrorMsg());\n");
|
|
||||||
// zend_error() should never return with the parameters we pass, but if it
|
|
||||||
// does, we really don't want to let SWIG_FAIL() return. This also avoids
|
|
||||||
// a warning about returning from a function marked as "__noreturn__".
|
|
||||||
Append(s_header, " abort();\n");
|
|
||||||
Append(s_header, "}\n\n");
|
|
||||||
|
|
||||||
Printf(s_header, "static void %s_init_globals(zend_%s_globals *globals ) {\n", module, module);
|
Printf(s_header, "static void %s_init_globals(zend_%s_globals *globals ) {\n", module, module);
|
||||||
Printf(s_header, " globals->error_msg = default_error_msg;\n");
|
Printf(s_header, " globals->error_msg = default_error_msg;\n");
|
||||||
Printf(s_header, " globals->error_code = default_error_code;\n");
|
Printf(s_header, " globals->error_code = default_error_code;\n");
|
||||||
|
@ -857,7 +843,8 @@ public:
|
||||||
Printf(f->code, "SWIG_ErrorCode() = E_ERROR;\n");
|
Printf(f->code, "SWIG_ErrorCode() = E_ERROR;\n");
|
||||||
Printf(f->code, "SWIG_ErrorMsg() = \"No matching function for overloaded '%s'\";\n", symname);
|
Printf(f->code, "SWIG_ErrorMsg() = \"No matching function for overloaded '%s'\";\n", symname);
|
||||||
Printv(f->code, "SWIG_FAIL();\n", NIL);
|
Printv(f->code, "SWIG_FAIL();\n", NIL);
|
||||||
|
Printv(f->code, "thrown:\n", NIL);
|
||||||
|
Printv(f->code, "return;\n", NIL);
|
||||||
Printv(f->code, "}\n", NIL);
|
Printv(f->code, "}\n", NIL);
|
||||||
Wrapper_print(f, s_wrappers);
|
Wrapper_print(f, s_wrappers);
|
||||||
|
|
||||||
|
@ -2060,25 +2047,6 @@ public:
|
||||||
p = nextSibling(p);
|
p = nextSibling(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* exception handling */
|
|
||||||
bool error_used_in_typemap = false;
|
|
||||||
tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0);
|
|
||||||
if (!tm) {
|
|
||||||
tm = Getattr(n, "feature:director:except");
|
|
||||||
if (tm)
|
|
||||||
tm = Copy(tm);
|
|
||||||
}
|
|
||||||
if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) {
|
|
||||||
if (Replaceall(tm, "$error", "error")) {
|
|
||||||
/* Only declare error if it is used by the typemap. */
|
|
||||||
error_used_in_typemap = true;
|
|
||||||
Append(w->code, "int error = SUCCESS;\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Delete(tm);
|
|
||||||
tm = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!idx) {
|
if (!idx) {
|
||||||
Printf(w->code, "zval *args = NULL;\n");
|
Printf(w->code, "zval *args = NULL;\n");
|
||||||
} else {
|
} else {
|
||||||
|
@ -2098,25 +2066,27 @@ public:
|
||||||
Append(w->code, "#if PHP_MAJOR_VERSION < 8\n");
|
Append(w->code, "#if PHP_MAJOR_VERSION < 8\n");
|
||||||
Printf(w->code, "zval swig_funcname;\n");
|
Printf(w->code, "zval swig_funcname;\n");
|
||||||
Printf(w->code, "ZVAL_STRINGL(&swig_funcname, \"%s\", %d);\n", funcname, strlen(funcname));
|
Printf(w->code, "ZVAL_STRINGL(&swig_funcname, \"%s\", %d);\n", funcname, strlen(funcname));
|
||||||
if (error_used_in_typemap) {
|
|
||||||
Append(w->code, "error = ");
|
|
||||||
}
|
|
||||||
Printf(w->code, "call_user_function(EG(function_table), &swig_self, &swig_funcname, &swig_zval_result, %d, args);\n", idx);
|
Printf(w->code, "call_user_function(EG(function_table), &swig_self, &swig_funcname, &swig_zval_result, %d, args);\n", idx);
|
||||||
Append(w->code, "#else\n");
|
Append(w->code, "#else\n");
|
||||||
Printf(w->code, "zend_string *swig_funcname = zend_string_init(\"%s\", %d, 0);\n", funcname, strlen(funcname));
|
Printf(w->code, "zend_string *swig_funcname = zend_string_init(\"%s\", %d, 0);\n", funcname, strlen(funcname));
|
||||||
Append(w->code, "zend_function *swig_zend_func = zend_std_get_method(&Z_OBJ(swig_self), swig_funcname, NULL);\n");
|
Append(w->code, "zend_function *swig_zend_func = zend_std_get_method(&Z_OBJ(swig_self), swig_funcname, NULL);\n");
|
||||||
Append(w->code, "zend_string_release(swig_funcname);\n");
|
Append(w->code, "zend_string_release(swig_funcname);\n");
|
||||||
Printf(w->code, "if (swig_zend_func) zend_call_known_instance_method(swig_zend_func, Z_OBJ(swig_self), &swig_zval_result, %d, args);\n", idx);
|
Printf(w->code, "if (swig_zend_func) zend_call_known_instance_method(swig_zend_func, Z_OBJ(swig_self), &swig_zval_result, %d, args);\n", idx);
|
||||||
if (error_used_in_typemap) {
|
|
||||||
Append(w->code, "else error = FAILURE;\n");
|
|
||||||
}
|
|
||||||
Append(w->code, "#endif\n");
|
Append(w->code, "#endif\n");
|
||||||
Append(w->code, "}\n");
|
|
||||||
|
|
||||||
if (tm) {
|
/* exception handling */
|
||||||
Printv(w->code, Str(tm), "\n", NIL);
|
tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0);
|
||||||
Delete(tm);
|
if (!tm) {
|
||||||
|
tm = Getattr(n, "feature:director:except");
|
||||||
|
if (tm)
|
||||||
|
tm = Copy(tm);
|
||||||
}
|
}
|
||||||
|
if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) {
|
||||||
|
Replaceall(tm, "$error", "EG(exception)");
|
||||||
|
Printv(w->code, Str(tm), "\n", NIL);
|
||||||
|
}
|
||||||
|
Append(w->code, "}\n");
|
||||||
|
Delete(tm);
|
||||||
|
|
||||||
/* marshal return value from PHP to C/C++ type */
|
/* marshal return value from PHP to C/C++ type */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue