From 04bacf689b5c9ddc5b6d3ef84c281c3a499a00ad Mon Sep 17 00:00:00 2001 From: Olly Betts Date: Mon, 3 May 2021 16:00:30 +1200 Subject: Implement director-disown for PHP --- Lib/php/director.swg | 22 +++++++++++++++++++++- Source/Modules/php.cxx | 28 +++++++++++++++++++++------- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Lib/php/director.swg b/Lib/php/director.swg index 7a81cd518..ead731a48 100644 --- a/Lib/php/director.swg +++ b/Lib/php/director.swg @@ -8,6 +8,8 @@ #ifndef SWIG_DIRECTOR_PHP_HEADER_ #define SWIG_DIRECTOR_PHP_HEADER_ +#define SWIG_DIRECTOR_CAST(ARG) dynamic_cast(ARG) + #include #include #include @@ -76,16 +78,34 @@ namespace Swig { }; class Director { + private: + /* flag indicating whether the object is owned by PHP or C++ */ + mutable bool swig_disown_flag; + protected: // "mutable" so we can get a non-const pointer to it in const methods. mutable zval swig_self; typedef std::map swig_ownership_map; mutable swig_ownership_map swig_owner; + public: - Director(zval *self) { + Director(zval *self) : swig_disown_flag(false) { ZVAL_COPY_VALUE(&swig_self, self); } + ~Director() { + if (swig_disown_flag) { + Z_DELREF(swig_self); + } + } + + void swig_disown() const { + if (!swig_disown_flag) { + swig_disown_flag = true; + Z_ADDREF(swig_self); + } + } + static bool swig_is_overridden_method(const char *cname, zval *z) { zend_string * cname_str = zend_string_init(cname, strlen(cname), 0); zend_class_entry *ce = zend_lookup_class(cname_str); diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx index 9e52400b7..79c2bd567 100644 --- a/Source/Modules/php.cxx +++ b/Source/Modules/php.cxx @@ -110,7 +110,8 @@ static enum { membervar, staticmembervar, constructor, - directorconstructor + directorconstructor, + directordisown } wrapperType = standard; extern "C" { @@ -904,7 +905,7 @@ public: return false; } - void generate_magic_property_methods(String *baseClassExtend) { + void generate_magic_property_methods(Node *class_node, String *baseClassExtend) { if (Cmp(baseClassExtend, "Exception") == 0 || !is_class_wrapped(baseClassExtend)) { baseClassExtend = NULL; } @@ -944,8 +945,14 @@ public: Append(f->code, magic_set); } Printf(f->code, "\nelse if (strcmp(ZSTR_VAL(arg2),\"thisown\") == 0) {\n"); - Printf(f->code, "arg->newobject = zval_get_long(&args[1]);\n}\n\n"); - Printf(f->code, "else {\n"); + Printf(f->code, "arg->newobject = zval_get_long(&args[1]);\n"); + if (Swig_directorclass(class_node)) { + Printv(f->code, "if (arg->newobject == 0) {\n", + " Swig::Director *director = SWIG_DIRECTOR_CAST((", Getattr(class_node, "classtypeobj"), "*)(arg->ptr));\n", + " if (director) director->swig_disown();\n", + "}\n", NIL); + } + Printf(f->code, "} else {\n"); if (baseClassExtend) { Printf(f->code, "PHP_MN(%s___set)(INTERNAL_FUNCTION_PARAM_PASSTHRU);\n}\n", baseClassExtend); } else { @@ -1074,6 +1081,10 @@ public: } virtual int functionWrapper(Node *n) { + if (wrapperType == directordisown) { + // Handled via __set magic method - no explicit wrapper method wanted. + return SWIG_OK; + } String *name = GetChar(n, "name"); String *iname = GetChar(n, "sym:name"); SwigType *d = Getattr(n, "type"); @@ -1673,7 +1684,7 @@ public: Language::classHandler(n); print_creation_free_wrapper(n); - generate_magic_property_methods(baseClassExtend); + generate_magic_property_methods(n, baseClassExtend); Printf(all_cs_entry, " ZEND_FE_END\n};\n\n"); class_name = NULL; @@ -2190,8 +2201,11 @@ public: return status; } - int classDirectorDisown(Node *) { - return SWIG_OK; + int classDirectorDisown(Node *n) { + wrapperType = directordisown; + int result = Language::classDirectorDisown(n); + wrapperType = standard; + return result; } }; /* class PHP */ -- cgit v1.2.1