diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-04 15:11:46 +0100 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-04 15:11:46 +0100 |
commit | 200952ad4004f6ee5527598622505adbe84df8af (patch) | |
tree | a4fb92a86730c771e36abf421835ab01861ef41c /src | |
parent | 59cfe935248918c1151b300eb19496b76ed579a9 (diff) |
implemented cloning of objects
Diffstat (limited to 'src')
-rw-r--r-- | src/classbase.cpp | 156 |
1 files changed, 115 insertions, 41 deletions
diff --git a/src/classbase.cpp b/src/classbase.cpp index af707c4..debfa7d 100644 --- a/src/classbase.cpp +++ b/src/classbase.cpp @@ -37,71 +37,145 @@ static void deallocate_object(void *object TSRMLS_DC) } /** - * Function that is called to create space for a cloned object - * @param object The object to be cloned - * @param clone The address that should become the clone - */ -static void clone_object(void *object, void **clone TSRMLS_DC) -{ - // @todo implementation -} - -/** - * Function that is called when an instance of the class needs to be created. - * This function will create the C++ class, and the PHP object - * @param type Pointer to the class information - * @return zend_object_value The newly created object + * Retrieve our C++ implementation object + * @param entry + * @return ClassBase */ -static zend_object_value create_object(zend_class_entry *type TSRMLS_DC) +static ClassBase *cpp_class(zend_class_entry *entry) { - // allocate memory for the object - MixedObject *object = (MixedObject *)emalloc(sizeof(MixedObject)); + // we need the base class (in user space the class may have been overridden, + // but we are not interested in these user space classes) + while (entry->parent) entry = entry->parent; - // find base object (because the class may have been extended in user space) - zend_class_entry *base = type; - while (base->parent) base = base->parent; - - // retrieve the classinfo object #if PHP_VERSION_ID >= 50400 - const char *comment = base->info.user.doc_comment; + // retrieve the comment (it has a pointer hidden in it to the ClassBase object) + const char *comment = entry->info.user.doc_comment; #else - const char *comment = base->doc_comment; + // retrieve the comment php5.3 style (it has a pointer hidden in it to the ClassBase object) + const char *comment = entry->doc_comment; #endif // the first byte of the comment is an empty string (null character), but - // the next bytes contain a pointer to the ClassInfo class - ClassBase *info = *((ClassBase **)(comment + 1)); + // the next bytes contain a pointer to the ClassBase class + return *((ClassBase **)(comment + 1)); +} + +/** + * Create an object based on a certain class entry + * @param entry + * @return MixedObject + */ +static MixedObject *allocate_object(zend_class_entry *entry) +{ + // allocate memory for the object + MixedObject *result = (MixedObject *)emalloc(sizeof(MixedObject)); - // store the class - object->php.ce = type; + // store the class entry in the newly created object + result->php.ce = entry; +#if PHP_VERSION_ID < 50399 // the original create_object fills the initial object with the default properties, // we're going to do exactly the same. start with setting up a hashtable for the props - ALLOC_HASHTABLE(object->php.properties); + ALLOC_HASHTABLE(result->php.properties); // initialize the hash table - zend_hash_init(object->php.properties, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_init(result->php.properties, 0, NULL, ZVAL_PTR_DTOR, 0); - // initialize the properties -#if PHP_VERSION_ID < 50399 - zend_hash_copy(object->php.properties, &(type->default_properties), - (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)); + zend_hash_copy(result->php.properties, &entry->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)); #else - object_properties_init(&(object->php), type); + // version higher than 5.3 have an easier way to initialize + object_properties_init(&result->php, entry); #endif + + // done + return result; +} + +/** + * Forward declaration + */ +static zend_object_value clone_object(zval *val TSRMLS_DC); + +/** + * Store the mixed object in the PHP object cache + * @param object The object to store + * @param value The zend_object_value to initialize + */ +static void store(MixedObject *object, zend_object_value *value) +{ + // set the handlers + value->handlers = zend_get_std_object_handlers(); + + // we need a special handler for cloning + value->handlers->clone_obj = clone_object; + + // the destructor and clone handlers are set to NULL. I dont know why, but they do not + // seem to be necessary... + value->handle = zend_objects_store_put(object, NULL, deallocate_object, NULL TSRMLS_CC); +} + +/** + * Function that is called to create space for a cloned object + * @param val The object to be cloned + * @return zend_obejct_value The object to be created + */ +static zend_object_value clone_object(zval *val TSRMLS_DC) +{ + // @todo refactoring because there is a lot of double code here + + // retrieve the class entry linked to this object + auto *entry = zend_get_class_entry(val); + + // allocate memory for the new object + MixedObject *new_object = allocate_object(entry); + // retrieve the old object, which we are going to copy + MixedObject *old_object = (MixedObject *)zend_object_store_get_object(val); + + // we need the C++ class meta-information object + ClassBase *meta = cpp_class(entry); + // the thing we're going to return zend_object_value result; + + // store the object + store(new_object, &result); + + // clone the members + zend_objects_clone_members(&new_object->php, result, &old_object->php, Z_OBJ_HANDLE_P(val)); + + // finally, construct the cpp object + // @todo call this earlier, because it could fail + new_object->cpp = meta->clone(old_object->cpp, result); - // use default object handlers - result.handlers = zend_get_std_object_handlers(); + // done + return result; +} + +/** + * Function that is called when an instance of the class needs to be created. + * This function will create the C++ class, and the PHP object + * @param entry Pointer to the class information + * @return zend_object_value The newly created object + */ +static zend_object_value create_object(zend_class_entry *entry TSRMLS_DC) +{ + // allocate memory for the object + MixedObject *new_object = allocate_object(entry); + + // we need the C++ class meta-information object + ClassBase *meta = cpp_class(entry); + + // the thing we're going to return + zend_object_value result; - // put the object in the storage, and assign a method for deallocating and cloning - result.handle = zend_objects_store_put(object, NULL, deallocate_object, clone_object TSRMLS_CC); + // store the object + store(new_object, &result); // finally, construct the cpp object - object->cpp = info->construct(result); + // @todo call this earlier because it could fail + new_object->cpp = meta->construct(result); // done return result; @@ -115,7 +189,7 @@ ClassBase::~ClassBase() // destruct the entries if (_entries) delete[] _entries; - // php 5.3 deallocated the doc_comment by iself + // php 5.3 deallocates the doc_comment by iself #if PHP_VERSION_ID >= 50400 if (_comment) free(_comment); #endif |