diff --git a/Examples/test-suite/php/argout_runme.php b/Examples/test-suite/php/argout_runme.php index 9a62ed258..81fc01c1c 100644 --- a/Examples/test-suite/php/argout_runme.php +++ b/Examples/test-suite/php/argout_runme.php @@ -24,7 +24,7 @@ check::equal(5,intp_value($tr),"5==$tr"); # Check the voidhandle call, first with null $handle=NULL; voidhandle($handle); -check::resource($handle,"_p_void",'$handle is not _p_void'); +check::equal(get_class($handle),"SWIG\\_p_void",'$handle is not _p_void'); $handledata=handle($handle); check::equal($handledata,"Here it is","\$handledata != \"Here it is\""); diff --git a/Examples/test-suite/php/callback_runme.php b/Examples/test-suite/php/callback_runme.php index 590c282df..a0dc69fb3 100644 --- a/Examples/test-suite/php/callback_runme.php +++ b/Examples/test-suite/php/callback_runme.php @@ -2,7 +2,10 @@ require "tests.php"; require "callback.php"; + // In 2.0.6 and earlier, the constant was misnamed. -if (gettype(callback::FOO_I_Cb_Ptr) !== 'resource') die("callback::FOO_I_Cb_Ptr not a resource\n"); +check::equal(gettype(callback::FOO_I_Cb_Ptr), 'object', "callback::FOO_I_Cb_Ptr not an object"); + +check::equal(get_class(callback::FOO_I_Cb_Ptr), 'SWIG\_p_f_int__int', "callback::FOO_I_Cb_Ptr not expected class"); check::done(); diff --git a/Examples/test-suite/php/grouping_runme.php b/Examples/test-suite/php/grouping_runme.php index c040115d3..4b425e119 100644 --- a/Examples/test-suite/php/grouping_runme.php +++ b/Examples/test-suite/php/grouping_runme.php @@ -5,7 +5,7 @@ require "grouping.php"; check::functions(array("test1","test2","do_unary","negate")); check::equal(5,test1(5),"5==test1(5)"); -check::resource(test2(7),"_p_int","_p_int==test2(7)"); +check::equal(get_class(test2(7)),"SWIG\\_p_int","test2(7) is _p_int"); check::globals(array('test3')); //check::equal(37,test3_get(),'37==test3_get()'); diff --git a/Examples/test-suite/php/tests.php b/Examples/test-suite/php/tests.php index 8abdf667e..cbdb9e209 100644 --- a/Examples/test-suite/php/tests.php +++ b/Examples/test-suite/php/tests.php @@ -17,6 +17,10 @@ class check { if (! is_array($extra)) { $df=array_flip(get_declared_classes()); foreach($_original_classes as $class) unset($df[$class]); + // Filter out pointer wrappers such as SWIG/_p_int. + foreach(array_keys($df) as $class) { + if (preg_match('/^SWIG\\\\/', $class)) unset($df[$class]); + } $extra=array_keys($df); } return $extra; @@ -202,10 +206,6 @@ class check { return TRUE; } - static function resource($a,$b,$message) { - return check::equal(get_resource_type($a), $b, $message); - } - static function isnull($a,$message) { return check::equal($a,NULL,$message); } diff --git a/Lib/php/factory.i b/Lib/php/factory.i index 854720a86..54851944c 100644 --- a/Lib/php/factory.i +++ b/Lib/php/factory.i @@ -95,7 +95,7 @@ if (!dcast) { Type *dobj = dynamic_cast($1); if (dobj) { dcast = 1; - SWIG_SetZval(return_value, $needNewFlow, $owner, SWIG_as_voidptr(dobj), $descriptor(Type *)); + SWIG_SetZval(return_value, $needNewFlow-0, $owner, SWIG_as_voidptr(dobj), $descriptor(Type *)); } }%enddef @@ -104,6 +104,6 @@ if (!dcast) { int dcast = 0; %formacro(%_factory_dispatch, Types) if (!dcast) { - SWIG_SetZval(return_value, $needNewFlow, $owner, SWIG_as_voidptr($1), $descriptor); + SWIG_SetZval(return_value, $needNewFlow-0, $owner, SWIG_as_voidptr($1), $descriptor); } }%enddef diff --git a/Lib/php/php.swg b/Lib/php/php.swg index 889a7928c..37be5b4a2 100644 --- a/Lib/php/php.swg +++ b/Lib/php/php.swg @@ -383,7 +383,7 @@ SWIGTYPE &, SWIGTYPE && %{ - SWIG_SetZval($input, $needNewFlow, $owner, (void *)&$1, $1_descriptor); + SWIG_SetPointerZval($input, (void *)&$1, $1_descriptor, $owner); %} %typemap(out, fragment="swig_php_init_member_ptr") SWIGTYPE (CLASS::*) @@ -422,7 +422,7 @@ %typemap(directorin) SWIGTYPE %{ - SWIG_SetZval($input, $needNewFlow, 1, SWIG_as_voidptr(new $1_ltype((const $1_ltype &)$1)), $&1_descriptor); + SWIG_SetPointerZval($input, SWIG_as_voidptr(new $1_ltype((const $1_ltype &)$1)), $&1_descriptor, 1); %} %typemap(out) void ""; diff --git a/Lib/php/phpinit.swg b/Lib/php/phpinit.swg index 1665f5dc4..b4d25d29e 100644 --- a/Lib/php/phpinit.swg +++ b/Lib/php/phpinit.swg @@ -21,5 +21,6 @@ static int swig_member_ptr = 0; %} %fragment("swig_php_init_member_ptr", "init", fragment="swig_php_init_member_ptr2") %{ + // FIXME: Make this a class instead swig_member_ptr = zend_register_list_destructors_ex(swig_member_ptr_dtor, NULL, SWIG_MEMBER_PTR, module_number); %} diff --git a/Lib/php/phprun.swg b/Lib/php/phprun.swg index 749029333..6aea8e5a4 100644 --- a/Lib/php/phprun.swg +++ b/Lib/php/phprun.swg @@ -94,32 +94,21 @@ SWIG_SetPointerZval(zval *z, void *ptr, swig_type_info *type, int newobject) { ZVAL_NULL(z); return; } - if (type->clientdata) { - if ((newobject & 2) == 0) { - int resource_type = *(int *)(type->clientdata); - if (resource_type == 0) { - zend_error(E_ERROR, "Type: %s failed to register with zend", type->name); - } else { - /* Register the pointer as a resource. */ - swig_object_wrapper *value=(swig_object_wrapper *)emalloc(sizeof(swig_object_wrapper)); - value->ptr = ptr; - value->newobject = (newobject & 1); - value->type = type; - ZVAL_RES(z, zend_register_resource(value, resource_type)); - } - } else { - /* This code path is currently only used by directorin typemaps. */ - zend_class_entry *ce = (zend_class_entry*)(type->clientdata); - zend_object *obj = ce->create_object(ce); - swig_object_wrapper *value = php_fetch_object(obj); - value->ptr = ptr; - value->newobject = (newobject & 1); - value->type = type; - ZVAL_OBJ(z, obj); - } + + if (!type->clientdata) { + zend_error(E_ERROR, "Type: %s not registered with zend", type->name); return; } - zend_error(E_ERROR, "Type: %s not registered with zend",type->name); + + { + zend_class_entry *ce = (zend_class_entry*)(type->clientdata); + zend_object *obj = ce->create_object(ce); + swig_object_wrapper *value = php_fetch_object(obj); + value->ptr = ptr; + value->newobject = (newobject & 1); + value->type = type; + ZVAL_OBJ(z, obj); + } } /* This pointer conversion routine takes the native pointer p (along with @@ -127,13 +116,10 @@ SWIG_SetPointerZval(zval *z, void *ptr, swig_type_info *type, int newobject) { according to ty. The resultant pointer is returned, or NULL is returned if the pointer can't be cast. - Sadly PHP has no API to find a type name from a type id, only from an - instance of a resource of the type id, so we have to pass type_name as well. - This is called by SWIG_ConvertPtr which gets the type name from the - swig_object_wrapper or resource type. */ + swig_object_wrapper. */ static void * -SWIG_ConvertResourceData(void * p, const char *type_name, swig_type_info *ty) { +SWIG_ConvertPtrData(void * p, const char *type_name, swig_type_info *ty) { swig_cast_info *tc; void *result = 0; @@ -157,8 +143,7 @@ SWIG_ConvertResourceData(void * p, const char *type_name, swig_type_info *ty) { return result; } -/* We allow passing of a RESOURCE wrapping a non-class pointer or an OBJECT - wrapping a pointer to an object. */ +/* We wrap C/C++ pointers as PHP objects. */ static int SWIG_ConvertPtr(zval *z, void **ptr, swig_type_info *ty, int flags) { if (z == NULL) { @@ -172,24 +157,7 @@ SWIG_ConvertPtr(zval *z, void **ptr, swig_type_info *ty, int flags) { if (flags & SWIG_POINTER_DISOWN) { value->newobject = 0; } - *ptr = SWIG_ConvertResourceData(value->ptr, value->type->name, ty); - return (*ptr == NULL ? SWIG_ERROR : SWIG_OK); - } - case IS_RESOURCE: { - swig_object_wrapper *value; - void *p; - const char *type_name; - - if (Z_RES_TYPE_P(z) == -1) return -1; - value = (swig_object_wrapper *) Z_RES_VAL_P(z); - if (flags & SWIG_POINTER_DISOWN) { - value->newobject = 0; - } - p = value->ptr; - - type_name=zend_rsrc_list_get_rsrc_type(Z_RES_P(z)); - - *ptr = SWIG_ConvertResourceData(p, type_name, ty); + *ptr = SWIG_ConvertPtrData(value->ptr, value->type->name, ty); return (*ptr == NULL ? SWIG_ERROR : SWIG_OK); } case IS_NULL: @@ -202,18 +170,13 @@ SWIG_ConvertPtr(zval *z, void **ptr, swig_type_info *ty, int flags) { static void SWIG_SetZval(zval *zv, int newFlow, int newobject, void *ptr, swig_type_info *type) { - if (!ptr) { - ZVAL_NULL(zv); - return; - } - - if (newFlow) { - swig_object_wrapper *obj; - if (newFlow == 1) { - zend_class_entry *ce = (zend_class_entry*)type->clientdata; - ZVAL_OBJ(zv, ce->create_object(ce)); + if (newFlow > 1) { + if (!ptr) { + ZVAL_NULL(zv); + return; } - obj = SWIG_Z_FETCH_OBJ_P(zv); + + swig_object_wrapper * obj = SWIG_Z_FETCH_OBJ_P(zv); obj->ptr = ptr; obj->newobject = newobject; obj->type = type; diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx index da59a0bf9..9f03576c2 100644 --- a/Source/Modules/php.cxx +++ b/Source/Modules/php.cxx @@ -95,7 +95,7 @@ static String *fake_class_name() { */ static Hash *arginfo_used; -/* Track non-class pointer types that get wrapped as resources */ +/* Track non-class pointer types we need to to wrap */ static Hash *zend_types = 0; static int shadow = 1; @@ -131,30 +131,31 @@ static void print_creation_free_wrapper(Node *n) { Printf(s, "/* Garbage Collection Method for class %s */\n",class_name); Printf(s, "void %s_free_storage(zend_object *object) {\n",class_name); - Printf(s, " swig_object_wrapper *obj = 0;\n\n"); - Printf(s, " if(!object)\n\t return;\n\n"); - Printf(s, " obj = php_fetch_object(object);\n\n"); + Printf(s, " swig_object_wrapper *obj = 0;\n"); + Printf(s, " if (!object)\n"); + Printf(s, " return;\n"); + Printf(s, " obj = php_fetch_object(object);\n"); - // expand %delete typemap? + // expand %delete typemap instead of SWIG_remove? if (Getattr(n, "has_destructor")) { - Printf(s, " if(obj->newobject)\n"); + Printf(s, " if (obj->newobject)\n"); Printf(s, " SWIG_remove((%s *)obj->ptr);\n", Getattr(n, "classtype")); } - Printf(s, " zend_object_std_dtor(&obj->std);\n}\n\n\n"); + Printf(s, " zend_object_std_dtor(&obj->std);\n"); + Printf(s, "}\n\n"); Printf(s, "/* Object Creation Method for class %s */\n",class_name); Printf(s, "zend_object * %s_object_new(zend_class_entry *ce) {\n",class_name); Printf(s, " swig_object_wrapper *obj = (swig_object_wrapper*)zend_object_alloc(sizeof(swig_object_wrapper), ce);\n"); Printf(s, " zend_object_std_init(&obj->std, ce);\n"); Printf(s, " object_properties_init(&obj->std, ce);\n"); - Printf(s, " %s_object_handlers.offset = XtOffsetOf(swig_object_wrapper, std);\n",class_name); - Printf(s, " %s_object_handlers.free_obj = %s_free_storage;\n",class_name,class_name); - Printf(s, " %s_object_handlers.dtor_obj = zend_objects_destroy_object;\n",class_name); + Printf(s, " %s_object_handlers.offset = XtOffsetOf(swig_object_wrapper, std);\n", class_name); + Printf(s, " %s_object_handlers.free_obj = %s_free_storage;\n", class_name, class_name); Printf(s, " obj->std.handlers = &%s_object_handlers;\n obj->newobject = 1;\n return &obj->std;\n}\n\n\n",class_name); } -static void SwigPHP_emit_resource_registrations() { +static void SwigPHP_emit_pointer_type_registrations() { if (!zend_types) return; @@ -162,25 +163,65 @@ static void SwigPHP_emit_resource_registrations() { if (!ki.key) return; - // Write out custom destructor function - const char *rsrc_dtor_name = "_swig_default_rsrc_destroy"; - Printf(s_wrappers, "static ZEND_RSRC_DTOR_FUNC(%s) {\n", rsrc_dtor_name); - Printf(s_wrappers, " efree(res->ptr);\n"); - Printf(s_wrappers, "}\n"); + Printf(s_wrappers, "/* class object handlers for pointer wrappers */\n"); + Printf(s_wrappers, "static zend_object_handlers swig_ptr_object_handlers;\n\n"); + + Printf(s_wrappers, "/* Object Creation Method for pointer wrapping class */\n"); + Printf(s_wrappers, "static zend_object * swig_ptr_object_new(zend_class_entry *ce) {\n"); + Printf(s_wrappers, " swig_object_wrapper *obj = (swig_object_wrapper*)zend_object_alloc(sizeof(swig_object_wrapper), ce);\n"); + Printf(s_wrappers, " zend_object_std_init(&obj->std, ce);\n"); + Printf(s_wrappers, " object_properties_init(&obj->std, ce);\n"); + Printf(s_wrappers, " obj->std.handlers = &swig_ptr_object_handlers;\n"); + Printf(s_wrappers, " obj->newobject = 0;\n"); + Printf(s_wrappers, " return &obj->std;\n"); + Printf(s_wrappers, "}\n\n"); + + Printf(s_wrappers, "/* Implement __toString equivalent, since that worked for the old-style resource wrapped pointers. */\n"); + Append(s_wrappers, "#if PHP_MAJOR_VERSION < 8\n"); + Printf(s_wrappers, "static int swig_ptr_cast_object(zval *z, zval *retval, int type) {\n"); + Append(s_wrappers, "#else\n"); + Printf(s_wrappers, "static int swig_ptr_cast_object(zend_object *zobj, zval *retval, int type) {\n"); + Append(s_wrappers, "#endif\n"); + Printf(s_wrappers, " if (type == IS_STRING) {\n"); + Printf(s_wrappers, " char buf[80];\n"); + Append(s_wrappers, "#if PHP_MAJOR_VERSION < 8\n"); + Printf(s_wrappers, " swig_object_wrapper *obj = SWIG_Z_FETCH_OBJ_P(z);\n"); + Append(s_wrappers, "#else\n"); + Printf(s_wrappers, " swig_object_wrapper *obj = php_fetch_object(zobj);\n"); + Append(s_wrappers, "#endif\n"); + Printv(s_wrappers, " sprintf(buf, \"SWIGPointer(%p,owned=%d)\", obj->ptr, obj->newobject);\n", NIL); + Printf(s_wrappers, " ZVAL_STRING(retval, buf);\n"); + Printf(s_wrappers, " return SUCCESS;\n"); + Printf(s_wrappers, " }\n"); + Printf(s_wrappers, " return FAILURE;\n"); + Printf(s_wrappers, "}\n\n"); + + Printf(s_wrappers, "static zend_function_entry swig_ptr_class_functions[] = {\n"); + Printf(s_wrappers, " ZEND_FE_END\n"); + Printf(s_wrappers, "};\n\n"); + + Printf(s_oinit, "\n /* Register classes to represent non-class pointer types */\n"); + Printf(s_oinit, " memcpy(&swig_ptr_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));\n"); + Printf(s_oinit, " swig_ptr_object_handlers.offset = XtOffsetOf(swig_object_wrapper, std);\n"); + Printf(s_oinit, " swig_ptr_object_handlers.cast_object = swig_ptr_cast_object;\n"); - Printf(s_oinit, "\n /* Register resource destructors for non-class pointer types */\n"); while (ki.key) { String *type = ki.key; - // declare le_swig to store php registration - Printf(s_vdecl, "static int le_swig%s=0; /* handle for %s */\n", type, type); + if (!s_creation) { + s_creation = NewStringEmpty(); + } - // register with php - Printf(s_oinit, " le_swig%s=zend_register_list_destructors_ex" - "(%s, NULL, SWIGTYPE%s->name, module_number);\n", type, rsrc_dtor_name, type); + Printf(s_creation, "/* class entry for pointer to %s */\n", type); + Printf(s_creation, "zend_class_entry *SWIGTYPE_%s_ce;\n\n", type); - // store php type in class struct - Printf(s_oinit, " SWIG_TypeClientData(SWIGTYPE%s,&le_swig%s);\n", type, type); + Printf(s_oinit, "{\n"); + Printf(s_oinit, " zend_class_entry SWIGTYPE_%s_internal_ce;\n", type); + Printf(s_oinit, " INIT_CLASS_ENTRY(SWIGTYPE_%s_internal_ce, \"%s\\\\%s\", swig_ptr_class_functions);\n", type, "SWIG", type); + Printf(s_oinit, " SWIGTYPE_%s_ce = zend_register_internal_class(&SWIGTYPE_%s_internal_ce);\n", type, type); + Printf(s_oinit, " SWIGTYPE_%s_ce->create_object = swig_ptr_object_new;\n", type); + Printf(s_oinit, " SWIG_TypeClientData(SWIGTYPE%s,SWIGTYPE_%s_ce);\n", type, type); + Printf(s_oinit, "}\n\n"); ki = Next(ki); } @@ -450,7 +491,7 @@ public: /* Emit all of the code */ Language::top(n); - SwigPHP_emit_resource_registrations(); + SwigPHP_emit_pointer_type_registrations(); if (s_creation) { Dump(s_creation, s_header); Delete(s_creation); @@ -1284,7 +1325,6 @@ public: if ((tm = Getattr(p, "tmap:in"))) { Replaceall(tm, "$input", source); - Replaceall(tm, "$needNewFlow", paramType_valid ? (is_class_wrapped(paramType_class) ? "1" : "0") : "0"); Setattr(p, "emit:input", source); Printf(f->code, "%s\n", tm); if (i == 0 && Getattr(p, "self")) { @@ -1359,29 +1399,16 @@ public: } Setattr(n, "wrapper:method:name", wname); - String *retType_class = NULL; - bool retType_valid = is_class(d); - bool valid_wrapped_class = false; - bool constructorRenameOverload = false; - - if (retType_valid) { - retType_class = get_class_name(d); - Chop(retType_class); - valid_wrapped_class = is_class_wrapped(retType_class); - } - - if (constructor && Cmp(class_name, Getattr(n, "constructorHandler:sym:name")) != 0) { - constructorRenameOverload = true; - } + bool php_constructor = (constructor && Cmp(class_name, Getattr(n, "constructorHandler:sym:name")) == 0); /* emit function call */ String *actioncode = emit_action(n); if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { Replaceall(tm, "$input", Swig_cresult_name()); - Replaceall(tm, "$result", constructor ? (constructorRenameOverload ? "return_value" : "ZEND_THIS") : "return_value"); + Replaceall(tm, "$result", php_constructor ? "ZEND_THIS" : "return_value"); Replaceall(tm, "$owner", newobject ? "1" : "0"); - Replaceall(tm, "$needNewFlow", retType_valid ? (constructor ? (constructorRenameOverload ? "1" : "2") : (valid_wrapped_class ? "1" : "0")) : "0"); + Replaceall(tm, "$needNewFlow", php_constructor && is_class(d) ? "2" : "0"); Printf(f->code, "%s\n", tm); } else { Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); @@ -2019,11 +2046,6 @@ public: if ((tm = Getattr(p, "tmap:directorin")) != 0) { String *parse = Getattr(p, "tmap:directorin:parse"); if (!parse) { - if (is_class(Getattr(p, "type"))) { - Replaceall(tm, "$needNewFlow", "1"); - } else { - Replaceall(tm, "$needNewFlow", "0"); - } String *input = NewStringf("&args[%d]", idx++); Setattr(p, "emit:directorinput", input); Replaceall(tm, "$input", input);