php: Wrap classes using only swig_object_wrapper
We no longer use PHP resources to wrap classes, and the proxy classes no longer has a _cPtr property.
This commit is contained in:
parent
0267ee374b
commit
40da8bcbb6
6 changed files with 83 additions and 203 deletions
|
|
@ -1008,8 +1008,8 @@ that derives from both the class in question and a special
|
|||
<tt>Swig::Director</tt> class. These new classes, referred to as director
|
||||
classes, can be loosely thought of as the C++ equivalent of the PHP
|
||||
proxy classes. The director classes store a pointer to their underlying
|
||||
PHP object. Indeed, this is quite similar to the "_cPtr" and "thisown"
|
||||
members of the PHP proxy classes.
|
||||
PHP object. Indeed, this is quite similar to <tt>struct swig_object_wrapper</tt>
|
||||
which is used to implement the PHP proxy classes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
@ -1064,12 +1064,12 @@ infinite loop.
|
|||
<p>
|
||||
One more point needs to be made about the relationship between director
|
||||
classes and proxy classes. When a proxy class instance is created in
|
||||
PHP, SWIG creates an instance of the original C++ class and assigns it
|
||||
to <tt>->_cPtr</tt>. This is exactly what happens without directors
|
||||
and is true even if directors are enabled for the particular class in
|
||||
question. When a class <i>derived</i> from a proxy class is created,
|
||||
however, SWIG then creates an instance of the corresponding C++ director
|
||||
class. The reason for this difference is that user-defined subclasses
|
||||
PHP, SWIG creates an instance of the original C++ class and stores it
|
||||
in the <tt>struct swig_object_wrapper</tt>. This is true whether or not
|
||||
directors are enabled for the particular class in question. However
|
||||
when a class <i>derived</i> from a proxy class is created, SWIG instead
|
||||
creates an instance of the corresponding C++ director class.
|
||||
The reason for this difference is that user-defined subclasses
|
||||
may override or extend methods of the original class, so the director
|
||||
class is needed to route calls to these methods correctly. For
|
||||
unmodified proxy classes, all methods are ultimately implemented in C++
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
%import "import_nomodule.h"
|
||||
|
||||
#if !defined(SWIGJAVA) && !defined(SWIGRUBY) && !defined(SWIGCSHARP) && !defined(SWIGD) && !defined(SWIGPYTHON_BUILTIN)
|
||||
#if !defined(SWIGJAVA) && !defined(SWIGRUBY) && !defined(SWIGCSHARP) && !defined(SWIGD) && !defined(SWIGPYTHON_BUILTIN) && !defined(SWIGPHP)
|
||||
|
||||
/**
|
||||
* The proxy class does not have Bar derived from Foo, yet an instance of Bar
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
* language modules).
|
||||
*
|
||||
* This violation of the type system is not possible in Java, C# and D due to
|
||||
* static type checking. It's also not (currently) possible in Ruby, but this may
|
||||
* be fixable (needs more investigation).
|
||||
* static type checking. It's also not (currently) possible in PHP or Ruby, but
|
||||
* this may be fixable (needs more investigation).
|
||||
*/
|
||||
|
||||
%newobject create_Foo;
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ $b = new Bar();
|
|||
$b->set($a);
|
||||
$c = $b->get();
|
||||
|
||||
// FIXME: This doesn't work for checking that they wrap the same C++ object
|
||||
// because the two objects have different PHP resources, and we can't easily
|
||||
// look inside those resources to see which C++ objects they refer to.
|
||||
//check::equal($a->_cPtr, $c->_cPtr, "_cPtr check failed");
|
||||
// FIXME: The python version checks that a.this == c.this, but we don't seem
|
||||
// to have a way to check this with the PHP bindings we generate.
|
||||
|
||||
check::done();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ check::classes(array('import_nomodule','Bar'));
|
|||
// now new vars
|
||||
check::globals(array());
|
||||
|
||||
// SWIGPHP doesn't currently support the "violation of the type system" which
|
||||
// is tested by this testcase.
|
||||
exit(0);
|
||||
|
||||
$f = import_nomodule::create_Foo();
|
||||
import_nomodule::test1($f,42);
|
||||
import_nomodule::delete_Foo($f);
|
||||
|
|
|
|||
|
|
@ -77,64 +77,40 @@ typedef struct {
|
|||
zend_object std;
|
||||
} swig_object_wrapper;
|
||||
|
||||
#define SWIG_Z_FETCH_OBJ_P(zv) php_fetch_object(Z_OBJ_P(zv))
|
||||
|
||||
static inline
|
||||
swig_object_wrapper * php_fetch_object(zend_object *obj) {
|
||||
return (swig_object_wrapper *)((char *)obj - XtOffsetOf(swig_object_wrapper, std));
|
||||
}
|
||||
|
||||
#define SWIG_as_voidptr(a) const_cast< void * >(static_cast< const void * >(a))
|
||||
|
||||
static void
|
||||
SWIG_SetPointerZval(zval *z, void *ptr, swig_type_info *type, int newobject) {
|
||||
/*
|
||||
* First test for Null pointers. Return those as PHP native NULL
|
||||
*/
|
||||
if (!ptr ) {
|
||||
// Return PHP NULL for a C/C++ NULL pointer.
|
||||
if (!ptr) {
|
||||
ZVAL_NULL(z);
|
||||
return;
|
||||
}
|
||||
if (type->clientdata) {
|
||||
swig_object_wrapper *value;
|
||||
if (! (*(int *)(type->clientdata)))
|
||||
zend_error(E_ERROR, "Type: %s failed to register with zend",type->name);
|
||||
value=(swig_object_wrapper *)emalloc(sizeof(swig_object_wrapper));
|
||||
value->ptr=ptr;
|
||||
value->newobject=(newobject & 1);
|
||||
if ((newobject & 2) == 0) {
|
||||
/* Just register the pointer as a resource. */
|
||||
ZVAL_RES(z, zend_register_resource(value, *(int *)(type->clientdata)));
|
||||
int resource_type = *(int *)(type->clientdata);
|
||||
if (resource_type == 0)
|
||||
zend_error(E_ERROR, "Type: %s failed to register with zend", type->name);
|
||||
/* 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);
|
||||
ZVAL_RES(z, zend_register_resource(value, resource_type));
|
||||
} else {
|
||||
/*
|
||||
* Wrap the resource in an object, the resource will be accessible
|
||||
* via the "_cPtr" property. This code path is currently only used by
|
||||
* directorin typemaps.
|
||||
*/
|
||||
zend_class_entry *ce = NULL;
|
||||
const char *type_name = type->name+3; /* +3 so: _p_Foo -> Foo */
|
||||
size_t type_name_len;
|
||||
const char * p;
|
||||
|
||||
/* Namespace__Foo -> Foo */
|
||||
/* FIXME: ugly and goes wrong for classes with __ in their names. */
|
||||
while ((p = strstr(type_name, "__")) != NULL) {
|
||||
type_name = p + 2;
|
||||
}
|
||||
type_name_len = strlen(type_name);
|
||||
|
||||
if (SWIG_PREFIX_LEN > 0) {
|
||||
zend_string * classname = zend_string_alloc(SWIG_PREFIX_LEN + type_name_len, 0);
|
||||
memcpy(ZSTR_VAL(classname), SWIG_PREFIX, SWIG_PREFIX_LEN);
|
||||
memcpy(ZSTR_VAL(classname) + SWIG_PREFIX_LEN, type_name, type_name_len);
|
||||
ce = zend_lookup_class(classname);
|
||||
zend_string_release(classname);
|
||||
} else {
|
||||
zend_string * classname = zend_string_init(type_name, type_name_len, 0);
|
||||
ce = zend_lookup_class(classname);
|
||||
zend_string_release(classname);
|
||||
}
|
||||
if (ce == NULL) {
|
||||
/* class does not exist */
|
||||
object_init(z);
|
||||
} else {
|
||||
object_init_ex(z, ce);
|
||||
}
|
||||
|
||||
add_property_resource_ex(z, "_cPtr", sizeof("_cPtr") - 1, zend_register_resource(value, *(int *)(type->clientdata)));
|
||||
/* 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);
|
||||
ZVAL_OBJ(z, obj);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -197,30 +173,11 @@ SWIG_ConvertResourcePtr(zval *z, swig_type_info *ty, int flags) {
|
|||
|
||||
type_name=zend_rsrc_list_get_rsrc_type(Z_RES_P(z));
|
||||
|
||||
if (!type_name) {
|
||||
if (Z_TYPE_P(z) == IS_OBJECT) {
|
||||
#if PHP_MAJOR_VERSION < 8
|
||||
HashTable * ht = Z_OBJ_HT_P(z)->get_properties(z);
|
||||
#else
|
||||
HashTable * ht = Z_OBJ_HT_P(z)->get_properties(Z_OBJ_P(z));
|
||||
#endif
|
||||
zval * _cPtr = zend_hash_str_find(ht, "_cPtr", sizeof("_cPtr") - 1);
|
||||
type_name=zend_rsrc_list_get_rsrc_type(Z_RES_P(_cPtr));
|
||||
}
|
||||
}
|
||||
|
||||
return SWIG_ConvertResourceData(p, type_name, ty);
|
||||
}
|
||||
|
||||
#define SWIG_Z_FETCH_OBJ_P(zv) php_fetch_object(Z_OBJ_P(zv))
|
||||
|
||||
static inline
|
||||
swig_object_wrapper * php_fetch_object(zend_object *obj) {
|
||||
return (swig_object_wrapper *)((char *)obj - XtOffsetOf(swig_object_wrapper, std));
|
||||
}
|
||||
|
||||
/* We allow passing of a RESOURCE pointing to the object or an OBJECT whose
|
||||
_cPtr is a resource pointing to the object */
|
||||
/* We allow passing of a RESOURCE wrapping a non-class pointer or an OBJECT
|
||||
wrapping a pointer to an object. */
|
||||
static int
|
||||
SWIG_ConvertPtr(zval *z, void **ptr, swig_type_info *ty, int flags) {
|
||||
if (z == NULL) {
|
||||
|
|
@ -229,31 +186,10 @@ SWIG_ConvertPtr(zval *z, void **ptr, swig_type_info *ty, int flags) {
|
|||
}
|
||||
|
||||
switch (Z_TYPE_P(z)) {
|
||||
case IS_OBJECT: {
|
||||
#if PHP_MAJOR_VERSION < 8
|
||||
HashTable * ht = Z_OBJ_HT_P(z)->get_properties(z);
|
||||
#else
|
||||
HashTable * ht = Z_OBJ_HT_P(z)->get_properties(Z_OBJ_P(z));
|
||||
#endif
|
||||
if (ht) {
|
||||
zval * _cPtr = zend_hash_str_find(ht, "_cPtr", sizeof("_cPtr") - 1);
|
||||
if (_cPtr) {
|
||||
if (Z_TYPE_P(_cPtr) == IS_NULL) {
|
||||
/* FIXME - we need to check the type is compatible here! */
|
||||
*ptr = SWIG_Z_FETCH_OBJ_P(z)->ptr;
|
||||
return (*ptr == NULL ? -1 : 0);
|
||||
}
|
||||
if (Z_TYPE_P(_cPtr) == IS_INDIRECT) {
|
||||
_cPtr = Z_INDIRECT_P(_cPtr);
|
||||
}
|
||||
if (Z_TYPE_P(_cPtr) == IS_RESOURCE) {
|
||||
*ptr = SWIG_ConvertResourcePtr(_cPtr, ty, flags);
|
||||
return (*ptr == NULL ? -1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IS_OBJECT:
|
||||
/* FIXME - we need to check the type is compatible here! */
|
||||
*ptr = SWIG_Z_FETCH_OBJ_P(z)->ptr;
|
||||
return (*ptr == NULL ? -1 : 0);
|
||||
case IS_RESOURCE:
|
||||
*ptr = SWIG_ConvertResourcePtr(z, ty, flags);
|
||||
return (*ptr == NULL ? -1 : 0);
|
||||
|
|
@ -265,34 +201,8 @@ SWIG_ConvertPtr(zval *z, void **ptr, swig_type_info *ty, int flags) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
SWIG_pack_zval(zval *zv, void *ptr, int userNewObj) {
|
||||
swig_object_wrapper *obj = SWIG_Z_FETCH_OBJ_P(zv);
|
||||
obj->ptr = ptr;
|
||||
obj->newobject = userNewObj;
|
||||
}
|
||||
|
||||
static void
|
||||
SWIG_generalize_object(zval *zval_obj, void *ptr, int userNewObj, swig_type_info *type) {
|
||||
HashTable *ht = 0;
|
||||
|
||||
SWIG_pack_zval(zval_obj, ptr, userNewObj);
|
||||
#if PHP_MAJOR_VERSION < 8
|
||||
ht = Z_OBJ_HT_P(zval_obj)->get_properties(zval_obj);
|
||||
#else
|
||||
ht = Z_OBJ_HT_P(zval_obj)->get_properties(Z_OBJ_P(zval_obj));
|
||||
#endif
|
||||
|
||||
if(ht) {
|
||||
zval z;
|
||||
ZVAL_NULL(&z);
|
||||
zend_hash_str_add(ht, "_cPtr", sizeof("_cPtr") - 1, &z);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SWIG_SetZval( zval *zv, int newFlow, int userNewObj, void *ptr, swig_type_info *type, zend_object *std) {
|
||||
|
||||
if (!ptr) {
|
||||
ZVAL_NULL(zv);
|
||||
return;
|
||||
|
|
@ -301,9 +211,10 @@ SWIG_SetZval( zval *zv, int newFlow, int userNewObj, void *ptr, swig_type_info *
|
|||
if (newFlow) {
|
||||
if (newFlow == 1)
|
||||
ZVAL_OBJ(zv,std);
|
||||
SWIG_generalize_object(zv, ptr, userNewObj, type);
|
||||
}
|
||||
else {
|
||||
swig_object_wrapper *obj = SWIG_Z_FETCH_OBJ_P(zv);
|
||||
obj->ptr = ptr;
|
||||
obj->newobject = userNewObj;
|
||||
} else {
|
||||
SWIG_SetPointerZval(zv, ptr, type, userNewObj);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ static bool wrap_nonclass_global = true;
|
|||
// before PHP added namespaces.
|
||||
static bool wrap_nonclass_fake_class = true;
|
||||
|
||||
static String *NOTCLASS = NewString("Not a class");
|
||||
static Node *classnode = 0;
|
||||
static String *module = 0;
|
||||
static String *cap_module = 0;
|
||||
|
|
@ -98,7 +97,7 @@ static String *fake_class_name() {
|
|||
*/
|
||||
static Hash *arginfo_used;
|
||||
|
||||
/* Variables for using PHP classes */
|
||||
/* Track non-class pointer types that get wrapped as resources */
|
||||
static Hash *zend_types = 0;
|
||||
|
||||
static int shadow = 1;
|
||||
|
|
@ -139,6 +138,7 @@ static void print_creation_free_wrapper(Node *n) {
|
|||
Printf(s, " if(!object)\n\t return;\n\n");
|
||||
Printf(s, " obj = php_fetch_object(object);\n\n");
|
||||
|
||||
// expand %delete typemap?
|
||||
if (Getattr(n, "destructor") != NULL) {
|
||||
Printf(s, " if(obj->newobject)\n");
|
||||
Printf(s, " SWIG_remove((%s *)obj->ptr);\n", Getattr(n, "classtype"));
|
||||
|
|
@ -158,59 +158,32 @@ static void print_creation_free_wrapper(Node *n) {
|
|||
}
|
||||
|
||||
static void SwigPHP_emit_resource_registrations() {
|
||||
Iterator ki;
|
||||
bool emitted_default_dtor = false;
|
||||
|
||||
if (!zend_types)
|
||||
return;
|
||||
|
||||
ki = First(zend_types);
|
||||
if (ki.key)
|
||||
Printf(s_oinit, "\n /* Register resource destructors for pointer types */\n");
|
||||
Iterator ki = First(zend_types);
|
||||
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_oinit, "\n /* Register resource destructors for non-class pointer types */\n");
|
||||
while (ki.key) {
|
||||
DOH *key = ki.key;
|
||||
Node *class_node = ki.item;
|
||||
String *human_name = key;
|
||||
String *rsrc_dtor_name = NULL;
|
||||
|
||||
// write out body
|
||||
if (class_node != NOTCLASS) {
|
||||
String *destructor = Getattr(class_node, "destructor");
|
||||
human_name = Getattr(class_node, "sym:name");
|
||||
if (!human_name)
|
||||
human_name = Getattr(class_node, "name");
|
||||
// Do we have a known destructor for this type?
|
||||
if (destructor) {
|
||||
rsrc_dtor_name = NewStringf("_wrap_destroy%s", key);
|
||||
// Write out custom destructor function
|
||||
Printf(s_wrappers, "static ZEND_RSRC_DTOR_FUNC(%s) {\n", rsrc_dtor_name);
|
||||
Printf(s_wrappers, " %s(res, SWIGTYPE%s->name);\n", destructor, key);
|
||||
Printf(s_wrappers, "}\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!rsrc_dtor_name) {
|
||||
rsrc_dtor_name = NewString("_swig_default_rsrc_destroy");
|
||||
if (!emitted_default_dtor) {
|
||||
// Write out custom destructor function
|
||||
Printf(s_wrappers, "static ZEND_RSRC_DTOR_FUNC(%s) {\n", rsrc_dtor_name);
|
||||
Printf(s_wrappers, " efree(res->ptr);\n");
|
||||
Printf(s_wrappers, "}\n");
|
||||
emitted_default_dtor = true;
|
||||
}
|
||||
}
|
||||
String *type = ki.key;
|
||||
|
||||
// declare le_swig<mangled> to store php registration
|
||||
Printf(s_vdecl, "static int le_swig%s=0; /* handle for %s */\n", key, human_name);
|
||||
Printf(s_vdecl, "static int le_swig%s=0; /* handle for %s */\n", type, type);
|
||||
|
||||
// register with php
|
||||
Printf(s_oinit, " le_swig%s=zend_register_list_destructors_ex"
|
||||
"(%s, NULL, SWIGTYPE%s->name, module_number);\n", key, rsrc_dtor_name, key);
|
||||
"(%s, NULL, SWIGTYPE%s->name, module_number);\n", type, rsrc_dtor_name, type);
|
||||
|
||||
// store php type in class struct
|
||||
Printf(s_oinit, " SWIG_TypeClientData(SWIGTYPE%s,&le_swig%s);\n", key, key);
|
||||
|
||||
Delete(rsrc_dtor_name);
|
||||
Printf(s_oinit, " SWIG_TypeClientData(SWIGTYPE%s,&le_swig%s);\n", type, type);
|
||||
|
||||
ki = Next(ki);
|
||||
}
|
||||
|
|
@ -1827,9 +1800,9 @@ public:
|
|||
}
|
||||
|
||||
if (baseClassExtend && (exceptionClassFlag || is_class_wrapped(baseClassExtend))) {
|
||||
Printf(s_oinit, " SWIGTYPE_%s_ce = zend_register_internal_class_ex(&SWIGTYPE_%s_internal_ce, SWIGTYPE_%s_ce);\n", class_name , class_name, baseClassExtend);
|
||||
Printf(s_oinit, " SWIGTYPE_%s_ce = zend_register_internal_class_ex(&SWIGTYPE_%s_internal_ce, SWIGTYPE_%s_ce);\n", class_name, class_name, baseClassExtend);
|
||||
} else {
|
||||
Printf(s_oinit, " SWIGTYPE_%s_ce = zend_register_internal_class(&SWIGTYPE_%s_internal_ce);\n", class_name , class_name);
|
||||
Printf(s_oinit, " SWIGTYPE_%s_ce = zend_register_internal_class(&SWIGTYPE_%s_internal_ce);\n", class_name, class_name);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -1847,7 +1820,7 @@ public:
|
|||
String *interface = Getitem(interface_list, Iterator-1);
|
||||
String *interface_ce = NewStringEmpty();
|
||||
Printf(interface_ce, "php_%s_interface_ce_%d" , class_name , Iterator);
|
||||
Printf(s_oinit, " zend_class_entry *%s = zend_lookup_class(zend_string_init(\"%s\", sizeof(\"%s\") - 1, 0));\n", interface_ce , interface, interface);
|
||||
Printf(s_oinit, " zend_class_entry *%s = zend_lookup_class(zend_string_init(\"%s\", sizeof(\"%s\") - 1, 0));\n", interface_ce, interface, interface);
|
||||
Append(append_interface, interface_ce);
|
||||
Append(append_interface, " ");
|
||||
}
|
||||
|
|
@ -1859,7 +1832,9 @@ public:
|
|||
|
||||
Printf(s_oinit, " SWIGTYPE_%s_ce->create_object = %s_object_new;\n", class_name, class_name);
|
||||
Printf(s_oinit, " memcpy(&%s_object_handlers,zend_get_std_object_handlers(), sizeof(zend_object_handlers));\n", class_name);
|
||||
Printf(s_oinit, " %s_object_handlers.clone_obj = NULL;\n}\n\n", class_name);
|
||||
Printf(s_oinit, " %s_object_handlers.clone_obj = NULL;\n", class_name);
|
||||
Printf(s_oinit, " SWIG_TypeClientData(SWIGTYPE_p%s,SWIGTYPE_%s_ce);\n", SwigType_manglestr(Getattr(n, "classtypeobj")), class_name);
|
||||
Printf(s_oinit, "}\n\n");
|
||||
|
||||
classnode = n;
|
||||
Language::classHandler(n);
|
||||
|
|
@ -2453,29 +2428,21 @@ public:
|
|||
|
||||
static PHP *maininstance = 0;
|
||||
|
||||
// We use this function to be able to write out zend_register_list_destructor_ex
|
||||
// lines for most things in the type table
|
||||
// Collect non-class pointer types from the type table so we can set up PHP
|
||||
// resource types for them later.
|
||||
//
|
||||
// NOTE: it's a function NOT A PHP::METHOD
|
||||
extern "C" {
|
||||
static void typetrace(const SwigType *ty, String *mangled, String *clientdata) {
|
||||
Node *class_node;
|
||||
if (!zend_types) {
|
||||
zend_types = NewHash();
|
||||
}
|
||||
// we want to know if the type which reduced to this has a constructor
|
||||
if ((class_node = maininstance->classLookup(ty))) {
|
||||
if (!Getattr(zend_types, mangled)) {
|
||||
// OK it may have been set before by a different SwigType but it would
|
||||
// have had the same underlying class node I think
|
||||
// - it is certainly required not to have different originating class
|
||||
// nodes for the same SwigType
|
||||
Setattr(zend_types, mangled, class_node);
|
||||
if (maininstance->classLookup(ty) == NULL) {
|
||||
// a non-class pointer
|
||||
if (!zend_types) {
|
||||
zend_types = NewHash();
|
||||
}
|
||||
} else { // a non-class pointer
|
||||
Setattr(zend_types, mangled, NOTCLASS);
|
||||
Setattr(zend_types, mangled, mangled);
|
||||
}
|
||||
if (r_prevtracefunc)
|
||||
(*r_prevtracefunc) (ty, mangled, (String *) clientdata);
|
||||
(*r_prevtracefunc) (ty, mangled, clientdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue