diff options
Diffstat (limited to 'zend/classimpl.cpp')
-rw-r--r-- | zend/classimpl.cpp | 347 |
1 files changed, 142 insertions, 205 deletions
diff --git a/zend/classimpl.cpp b/zend/classimpl.cpp index 5c339e9..75191f5 100644 --- a/zend/classimpl.cpp +++ b/zend/classimpl.cpp @@ -7,6 +7,7 @@ * @copyright 2014 Copernica BV */ #include "includes.h" +#include <cstring> /** * Set up namespace @@ -19,12 +20,10 @@ namespace Php { ClassImpl::~ClassImpl() { // destruct the entries - if (_entries) delete[] _entries; + delete[] _entries; -#if PHP_VERSION_ID >= 50400 - // on newer php versions, we have allocated the command to hide a pointer in it - if (_self) free(_self); -#endif + // free the stored pointer + if (_self) zend_string_release(_self); } /** @@ -38,8 +37,6 @@ ClassImpl::~ClassImpl() */ static ClassImpl *self(zend_class_entry *entry) { -#if PHP_VERSION_ID >= 50400 - /** * somebody could have extended this class from PHP userland, in which * case trying to dereference the doc_comment would result in a disaster @@ -58,37 +55,18 @@ static ClassImpl *self(zend_class_entry *entry) * the string, in case PHP tries to read it) and after that the pointer * and we leave the doc_comment_len at 0. */ - while (entry->parent && (entry->info.user.doc_comment == nullptr || entry->info.user.doc_comment_len > 0)) + while (entry->parent && (entry->info.user.doc_comment == nullptr || ZSTR_LEN(entry->info.user.doc_comment) > 0)) { // we did not create this class entry, but luckily we have a parent entry = entry->parent; } // retrieve the comment (it has a pointer hidden in it to the ClassBase object) - const char *comment = entry->info.user.doc_comment; + const char *comment = ZSTR_VAL(entry->info.user.doc_comment); // the first byte of the comment is an empty string (null character), but // the next bytes contain a pointer to the ClassBase class return *((ClassImpl **)(comment + 1)); -#else - - /** - * This is likely not correct: If the class was extended using PHP-CPP - * itself, we should retrieve the ClassImpl directly, however there is - * no sane way to check this here, unlike in PHP 5.4. - * - * We therefore always go to the very base, of which we are sure that - * we are the implementers. This way - at least - we don't cause any - * segfaults. - */ - while (entry->parent) entry = entry->parent; - - // on php 5.3 we store the pointer to impl after the name in the entry - ClassImpl** impl = (ClassImpl**)(entry->name + 1 + entry->name_length); - - // return the actual implementation - return *impl; -#endif } /** @@ -113,13 +91,11 @@ struct CallData void ClassImpl::callMethod(INTERNAL_FUNCTION_PARAMETERS) { // retrieve the originally called (and by us allocated) function object - // (this was copied from the zend engine source code, code looks way too - // ugly to be made by me) - CallData *data = (CallData *)EG(current_execute_data)->function_state.function; + auto *data = (CallData *)execute_data->func; zend_internal_function *func = &data->func; // retrieve the function name - const char *name = func->function_name; + const char *name = ZSTR_VAL(func->function_name); ClassBase *meta = data->self->_base; // the data structure was allocated by ourselves in the getMethod or @@ -134,7 +110,7 @@ void ClassImpl::callMethod(INTERNAL_FUNCTION_PARAMETERS) Value result(return_value, true); // construct parameters - ParametersImpl params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC); + ParametersImpl params(getThis(), ZEND_NUM_ARGS() TSRMLS_CC); // retrieve the base object Base *base = params.object(); @@ -162,9 +138,7 @@ void ClassImpl::callMethod(INTERNAL_FUNCTION_PARAMETERS) void ClassImpl::callInvoke(INTERNAL_FUNCTION_PARAMETERS) { // retrieve the originally called (and by us allocated) function object - // (this was copied from the zend engine source code, code looks way too - // ugly to be made by me) - CallData *data = (CallData *)EG(current_execute_data)->function_state.function; + auto *data = (CallData *)execute_data->func; // get self reference ClassBase *meta = data->self->_base; @@ -181,7 +155,7 @@ void ClassImpl::callInvoke(INTERNAL_FUNCTION_PARAMETERS) Value result(return_value, true); // construct parameters - ParametersImpl params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC); + ParametersImpl params(getThis(), ZEND_NUM_ARGS() TSRMLS_CC); // retrieve the base object Base *base = params.object(); @@ -203,17 +177,14 @@ void ClassImpl::callInvoke(INTERNAL_FUNCTION_PARAMETERS) /** * Method that returns the function definition of the __call function - * @param object_ptr - * @param method_name - * @param method_len + * + * @param object Pointer to the object from which we want to retrieve the member function + * @param method The method that we want information about + * @param key ??? * @param tsrm_ls * @return zend_function */ -#if PHP_VERSION_ID < 50399 -zend_function *ClassImpl::getMethod(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) -#else -zend_function *ClassImpl::getMethod(zval **object_ptr, char *method_name, int method_len, const zend_literal *key TSRMLS_DC) -#endif +zend_function *ClassImpl::getMethod(zend_object **object, zend_string *method, const zval *key TSRMLS_DC) { // something strange about the Zend engine (once more). The structure with // object-handlers has a get_method and call_method member. When a function is @@ -224,17 +195,13 @@ zend_function *ClassImpl::getMethod(zval **object_ptr, char *method_name, int me // first we'll check if the default handler does not have an implementation, // in that case the method is probably already implemented as a regular method -#if PHP_VERSION_ID < 50399 - auto *defaultFunction = std_object_handlers.get_method(object_ptr, method_name, method_len TSRMLS_CC); -#else - auto *defaultFunction = std_object_handlers.get_method(object_ptr, method_name, method_len, key TSRMLS_CC); -#endif + auto *defaultFunction = std_object_handlers.get_method(object, method, key TSRMLS_CC); // did the default implementation do anything? if (defaultFunction) return defaultFunction; // retrieve the class entry linked to this object - auto *entry = zend_get_class_entry(*object_ptr TSRMLS_CC); + auto *entry = (*object)->ce; // this is peculiar behavior of the zend engine, we first are going to dynamically // allocate memory holding all the properties of the __call method (we initially @@ -254,7 +221,7 @@ zend_function *ClassImpl::getMethod(zval **object_ptr, char *method_name, int me function->required_num_args = 0; function->scope = entry; function->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; - function->function_name = method_name; + function->function_name = method; // store pointer to ourselves data->self = self(entry); @@ -266,21 +233,18 @@ zend_function *ClassImpl::getMethod(zval **object_ptr, char *method_name, int me /** * Method that is called right before a static method call is attempted - * @param entry - * @param method - * @param method_len + * + * @param entry The class entry to find the static function in + * @param method The method to get information about + * @param key ??? * @param tsrm_ls * @return zend_function */ -zend_function *ClassImpl::getStaticMethod(zend_class_entry *entry, char* method, int method_len TSRMLS_DC) +zend_function *ClassImpl::getStaticMethod(zend_class_entry *entry, zend_string *method TSRMLS_DC) { // first we'll check if the default handler does not have an implementation, // in that case the method is probably already implemented as a regular method -#if PHP_VERSION_ID < 50399 - auto *defaultFunction = zend_std_get_static_method(entry, method, method_len TSRMLS_CC); -#else - auto *defaultFunction = zend_std_get_static_method(entry, method, method_len, nullptr TSRMLS_CC); -#endif + auto *defaultFunction = zend_std_get_static_method(entry, method, nullptr TSRMLS_CC); // did the default implementation do anything? if (defaultFunction) return defaultFunction; @@ -318,7 +282,7 @@ zend_function *ClassImpl::getStaticMethod(zend_class_entry *entry, char* method, * @param tsrm_ls * @return int */ -int ClassImpl::getClosure(zval *object, zend_class_entry **entry_ptr, zend_function **func, zval **object_ptr TSRMLS_DC) +int ClassImpl::getClosure(zval *object, zend_class_entry **entry_ptr, zend_function **func, zend_object **object_ptr TSRMLS_DC) { // it is really unbelievable how the Zend engine manages to implement every feature // in a complete different manner. You would expect the __invoke() and the @@ -327,9 +291,6 @@ int ClassImpl::getClosure(zval *object, zend_class_entry **entry_ptr, zend_funct // to fill the function parameter with all information about the invoke() // method that is going to get called - // retrieve the class entry linked to this object - auto *entry = zend_get_class_entry(object TSRMLS_CC); - // just like we did for getMethod(), we're going to dynamically allocate memory // with all information about the function auto *data = (CallData *)emalloc(sizeof(CallData)); @@ -342,12 +303,12 @@ int ClassImpl::getClosure(zval *object, zend_class_entry **entry_ptr, zend_funct function->arg_info = nullptr; function->num_args = 0; function->required_num_args = 0; - function->scope = entry; + function->scope = *entry_ptr; function->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; function->function_name = nullptr; // store pointer to ourselves - data->self = self(entry); + data->self = self(*entry_ptr); // assign this dynamically allocated variable to the func parameter // the cast is ok, because zend_internal_function is a member of the @@ -356,7 +317,7 @@ int ClassImpl::getClosure(zval *object, zend_class_entry **entry_ptr, zend_funct // the object_ptr should be filled with the object on which the method is // called (otherwise the Zend engine tries to call the method statically) - *object_ptr = object; + *object_ptr = Z_OBJ_P(object); // done return SUCCESS; @@ -397,12 +358,20 @@ zend_object_handlers *ClassImpl::objectHandlers() _handlers.get_method = &ClassImpl::getMethod; _handlers.get_closure = &ClassImpl::getClosure; + // register destructor and deallocator + _handlers.dtor_obj = &ClassImpl::destructObject; + _handlers.free_obj = &ClassImpl::freeObject; + // handler to cast to a different type _handlers.cast_object = &ClassImpl::cast; // method to compare two objects _handlers.compare_objects = &ClassImpl::compare; + // set the offset between our class implementation and + // the zend_object member in the allocated structure + _handlers.offset = ObjectImpl::offset(); + // remember that object is now initialized _initialized = true; @@ -433,10 +402,10 @@ int ClassImpl::compare(zval *val1, zval *val2 TSRMLS_DC) try { // retrieve the class entry linked to this object - auto *entry = zend_get_class_entry(val1 TSRMLS_CC); + auto *entry = Z_OBJCE_P(val1); // other object must be of the same type - if (entry != zend_get_class_entry(val2 TSRMLS_CC)) throw NotImplemented(); + if (entry != Z_OBJCE_P(val2)) throw NotImplemented(); // we need the C++ class meta-information object ClassBase *meta = self(entry)->_base; @@ -481,7 +450,7 @@ int ClassImpl::cast(zval *val, zval *retval, int type TSRMLS_DC) Base *object = ObjectImpl::find(val TSRMLS_CC)->object(); // retrieve the class entry linked to this object - auto *entry = zend_get_class_entry(val TSRMLS_CC); + auto *entry = Z_OBJCE_P(val); // we need the C++ class meta-information object ClassBase *meta = self(entry)->_base; @@ -489,7 +458,10 @@ int ClassImpl::cast(zval *val, zval *retval, int type TSRMLS_DC) // retval is not yet initialized --- and again feelings of disbelief, // frustration, wonder and anger come up when you see that there are not two // functions in the Zend engine that have a comparable API - INIT_PZVAL(retval); + // + // this function was removed, because it was supposedly no longer necessary + // can we get away with removing it here too? + // INIT_PZVAL(retval); // when the magic function it not implemented, an exception will be thrown, // and the extension may throw a Php::Exception @@ -539,13 +511,14 @@ int ClassImpl::cast(zval *val, zval *retval, int type TSRMLS_DC) /** * 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 + * + * @param val The object to be cloned + * @return zend_object The object to be created */ -zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC) +zend_object *ClassImpl::cloneObject(zval *val TSRMLS_DC) { // retrieve the class entry linked to this object - auto *entry = zend_get_class_entry(val TSRMLS_CC); + auto *entry = Z_OBJCE_P(val); // we need the C++ class meta-information object ClassImpl *impl = self(entry); @@ -564,27 +537,18 @@ zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC) // an exception back to the Zend engine) if (!cpp) zend_error(E_ERROR, "Unable to clone %s", entry->name); - // the thing we're going to return - zend_object_value result; - - // set the handlers - result.handlers = impl->objectHandlers(); - // store the object - ObjectImpl *new_object = new ObjectImpl(entry, cpp, 1 TSRMLS_CC); - - // store the object in the object cache - result.handle = new_object->handle(); + auto *new_object = new ObjectImpl(entry, cpp, impl->objectHandlers(), 1 TSRMLS_CC); // clone the members (this will also call the __clone() function if the user // had registered that as a visible method) - zend_objects_clone_members(new_object->php(), result, old_object->php(), Z_OBJ_HANDLE_P(val) TSRMLS_CC); + zend_objects_clone_members(new_object->php(), old_object->php() TSRMLS_CC); // was a custom clone method installed? If not we call the magic c++ __clone method if (!entry->clone) meta->callClone(cpp); // done - return result; + return new_object->php(); } /** @@ -642,10 +606,11 @@ int ClassImpl::countElements(zval *object, long *count TSRMLS_DC) * @param object The object on which it is called * @param offset The name of the property * @param type The type of the variable??? + * @param rv Pointer to where to store the data * @param tsrm_ls * @return zval */ -zval *ClassImpl::readDimension(zval *object, zval *offset, int type TSRMLS_DC) +zval *ClassImpl::readDimension(zval *object, zval *offset, int type, zval *rv TSRMLS_DC) { // what to do with the type? // @@ -675,7 +640,7 @@ zval *ClassImpl::readDimension(zval *object, zval *offset, int type TSRMLS_DC) try { // ArrayAccess is implemented, call function - return toZval(arrayaccess->offsetGet(offset), type); + return toZval(arrayaccess->offsetGet(offset), type, rv); } catch (Exception &exception) { @@ -692,7 +657,7 @@ zval *ClassImpl::readDimension(zval *object, zval *offset, int type TSRMLS_DC) if (!std_object_handlers.read_dimension) return nullptr; // call default - return std_object_handlers.read_dimension(object, offset, type TSRMLS_CC); + return std_object_handlers.read_dimension(object, offset, type, rv TSRMLS_CC); } } @@ -832,42 +797,66 @@ void ClassImpl::unsetDimension(zval *object, zval *member TSRMLS_DC) /** * Helper method to turn a property into a zval - * @param value - * @param type - * @return Value + * + * @param value The value to convert to a zval + * @param type The type of operation (read or write) + * @param rv Pointer to where to store the data + * @return The result (same as the ptr input) */ -zval *ClassImpl::toZval(Value &&value, int type) +zval *ClassImpl::toZval(Value &&value, int type, zval *rv) { - // because we do not want the value object to destruct the zval when - // it falls out of scope, we detach the zval from it, if this is a regular - // read operation we can do this right away - if (type == 0) return value.detach(false); - - // this is a more complicated read operation, the scripts wants to get - // deeper access to the returned value. This, however, is only possible - // if the value has more than once reference (if it has a refcount of one, - // the value object that we have here is the only instance of the zval, - // and it is simply impossible to return a reference or so - if (value.refcount() <= 1) return value.detach(false); - - // we're dealing with an editable zval, return a reference variable - return Value(value.detach(false), true).detach(false); + // the result zval that needs to be copied over + zval *result = nullptr; + + /** + * Because we do not want the value object to destruct the zval when + * it falls out of scope, we detach the zval from it, if this is a regular + * read operation we can do this right away. + * + * For write operations we need to check the refcount. If the refcount is + * only 1 (meaning the value object has the only reference) we cannot return + * a reference because there _is_ nothing to reference (the value will destruct) + */ + if (type == 0 || value.refcount() <= 1) + { + // first retrieve the value so we can copy it + result = value.detach(false); + } + // this is an editable zval, return a reference to it + else + { + // we're dealing with an editable zval, retrieve a reference variable + result = Value(value.detach(false), true).detach(false); + } + + // now copy the value over to the pointer + ZVAL_COPY_VALUE(rv, result); + + // if the zval has a reference count we must decrease it + Z_TRY_DELREF_P(result); + + // the pointer from the value may now be destroyed + // (it was allocated by the value and detached) + // we do not actually "destroy" the value here, + // even if the refcount reaches 0 here! + delete result; + + // return the pointer to the value + return rv; } /** * Function that is called when a property is read - * @param object - * @param name - * @param type - * @param key + * + * @param object The object on which it is called + * @param offset The name of the property + * @param type The type of the variable??? + * @param cache_slot The cache slot used + * @param rv Pointer to where to store the data * @param tsrm_ls * @return val */ -#if PHP_VERSION_ID < 50399 -zval *ClassImpl::readProperty(zval *object, zval *name, int type TSRMLS_DC) -#else -zval *ClassImpl::readProperty(zval *object, zval *name, int type, const zend_literal *key TSRMLS_DC) -#endif +zval *ClassImpl::readProperty(zval *object, zval *name, int type, void **cache_slot, zval *rv TSRMLS_DC) { // what to do with the type? // @@ -890,7 +879,7 @@ zval *ClassImpl::readProperty(zval *object, zval *name, int type, const zend_lit Base *base = ObjectImpl::find(object TSRMLS_CC)->object(); // retrieve the class entry linked to this object - auto *entry = zend_get_class_entry(object TSRMLS_CC); + auto *entry = Z_OBJCE_P(object); // we need the C++ class meta-information object ClassImpl *impl = self(entry); @@ -910,12 +899,12 @@ zval *ClassImpl::readProperty(zval *object, zval *name, int type, const zend_lit if (iter == impl->_properties.end()) { // retrieve value from the __get method - return toZval(meta->callGet(base, key), type); + return toZval(meta->callGet(base, key), type, rv); } else { // get the value - return toZval(iter->second->get(base), type); + return toZval(iter->second->get(base), type, rv); } } catch (const NotImplemented &exception) @@ -924,11 +913,7 @@ zval *ClassImpl::readProperty(zval *object, zval *name, int type, const zend_lit if (!std_object_handlers.read_property) return nullptr; // call default -#if PHP_VERSION_ID < 50399 - return std_object_handlers.read_property(object, name, type TSRMLS_CC); -#else - return std_object_handlers.read_property(object, name, type, key TSRMLS_CC); -#endif + return std_object_handlers.read_property(object, name, type, cache_slot, rv TSRMLS_CC); } catch (Exception &exception) { @@ -950,21 +935,17 @@ zval *ClassImpl::readProperty(zval *object, zval *name, int type, const zend_lit * @param object The object on which it is called * @param name The name of the property * @param value The new value - * @param key ??? + * @param cache_slot The cache slot used * @param tsrm_ls * @return zval */ -#if PHP_VERSION_ID < 50399 -void ClassImpl::writeProperty(zval *object, zval *name, zval *value TSRMLS_DC) -#else -void ClassImpl::writeProperty(zval *object, zval *name, zval *value, const zend_literal *key TSRMLS_DC) -#endif +void ClassImpl::writeProperty(zval *object, zval *name, zval *value, void **cache_slot TSRMLS_DC) { // retrieve the object and class Base *base = ObjectImpl::find(object TSRMLS_CC)->object(); // retrieve the class entry linked to this object - auto *entry = zend_get_class_entry(object TSRMLS_CC); + auto *entry = Z_OBJCE_P(object); // we need the C++ class meta-information object ClassImpl *impl = self(entry); @@ -1001,11 +982,7 @@ void ClassImpl::writeProperty(zval *object, zval *name, zval *value, const zend_ if (!std_object_handlers.write_property) return; // call the default -#if PHP_VERSION_ID < 50399 - std_object_handlers.write_property(object, name, value TSRMLS_CC); -#else - std_object_handlers.write_property(object, name, value, key TSRMLS_CC); -#endif + std_object_handlers.write_property(object, name, value, cache_slot TSRMLS_CC); } catch (Exception &exception) { @@ -1031,15 +1008,11 @@ void ClassImpl::writeProperty(zval *object, zval *name, zval *value, const zend_ * @param object The object on which it is called * @param name The name of the property to check * @param has_set_exists See above - * @param key ??? + * @param cache_slot The cache slot used * @param tsrm_ls * @return bool */ -#if PHP_VERSION_ID < 50399 -int ClassImpl::hasProperty(zval *object, zval *name, int has_set_exists TSRMLS_DC) -#else -int ClassImpl::hasProperty(zval *object, zval *name, int has_set_exists, const zend_literal *key TSRMLS_DC) -#endif +int ClassImpl::hasProperty(zval *object, zval *name, int has_set_exists, void **cache_slot TSRMLS_DC) { // the default implementation throws an exception, if we catch that // we know for sure that the user has not overridden the __isset method @@ -1049,7 +1022,7 @@ int ClassImpl::hasProperty(zval *object, zval *name, int has_set_exists, const z Base *base = ObjectImpl::find(object TSRMLS_CC)->object(); // retrieve the class entry linked to this object - auto *entry = zend_get_class_entry(object TSRMLS_CC); + auto *entry = Z_OBJCE_P(object); // we need the C++ class meta-information object ClassImpl *impl = self(entry); @@ -1082,11 +1055,7 @@ int ClassImpl::hasProperty(zval *object, zval *name, int has_set_exists, const z if (!std_object_handlers.has_property) return 0; // call default -#if PHP_VERSION_ID < 50399 - return std_object_handlers.has_property(object, name, has_set_exists TSRMLS_CC); -#else - return std_object_handlers.has_property(object, name, has_set_exists, key TSRMLS_CC); -#endif + return std_object_handlers.has_property(object, name, has_set_exists, cache_slot TSRMLS_CC); } catch (Exception &exception) { @@ -1106,21 +1075,17 @@ int ClassImpl::hasProperty(zval *object, zval *name, int has_set_exists, const z * * @param object The object on which it is called * @param member The member to remove - * @param key + * @param cache_slot The cache slot used * @param tsrm_ls */ -#if PHP_VERSION_ID < 50399 -void ClassImpl::unsetProperty(zval *object, zval *member TSRMLS_DC) -#else -void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *key TSRMLS_DC) -#endif +void ClassImpl::unsetProperty(zval *object, zval *member, void **cache_slot TSRMLS_DC) { // the default implementation throws an exception, if we catch that // we know for sure that the user has not overridden the __unset method try { // retrieve the class entry linked to this object - auto *entry = zend_get_class_entry(object TSRMLS_CC); + auto *entry = Z_OBJCE_P(object); // we need the C++ class meta-information object ClassImpl *impl = self(entry); @@ -1143,11 +1108,7 @@ void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *ke if (!std_object_handlers.unset_property) return; // call the default -#if PHP_VERSION_ID < 50399 - std_object_handlers.unset_property(object, member TSRMLS_CC); -#else - std_object_handlers.unset_property(object, member, key TSRMLS_CC); -#endif + std_object_handlers.unset_property(object, member, cache_slot TSRMLS_CC); } catch (Exception &exception) { @@ -1161,10 +1122,9 @@ void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *ke * Function that is called when an object is about to be destructed * This will call the magic __destruct method * @param object - * @param handle * @param tsrm_ls */ -void ClassImpl::destructObject(zend_object *object, zend_object_handle handle TSRMLS_DC) +void ClassImpl::destructObject(zend_object *object TSRMLS_DC) { // find object ObjectImpl *obj = ObjectImpl::find(object); @@ -1181,7 +1141,7 @@ void ClassImpl::destructObject(zend_object *object, zend_object_handle handle TS catch (const NotImplemented &exception) { // fallback on the default destructor call - zend_objects_destroy_object(object, handle TSRMLS_CC); + zend_objects_destroy_object(object TSRMLS_CC); } catch (Exception &exception) { @@ -1212,7 +1172,7 @@ void ClassImpl::freeObject(zend_object *object TSRMLS_DC) * @param tsrm_ls * @return zend_object_value The newly created object */ -zend_object_value ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC) +zend_object *ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC) { // we need the C++ class meta-information object ClassImpl *impl = self(entry); @@ -1225,20 +1185,11 @@ zend_object_value ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC) // the Zend engine) if (!cpp) zend_error(E_ERROR, "Unable to instantiate %s", entry->name); - // the thing we're going to return - zend_object_value result; - - // set the handlers - result.handlers = impl->objectHandlers(); - // create the object in the zend engine - ObjectImpl *object = new ObjectImpl(entry, cpp, 1 TSRMLS_CC); + auto *object = new ObjectImpl(entry, cpp, impl->objectHandlers(), 1 TSRMLS_CC); - // store the object in the object cache - result.handle = object->handle(); - - // done - return result; + // return the php object stored in the implementation + return object->php(); } /** @@ -1288,7 +1239,7 @@ zend_object_iterator *ClassImpl::getIterator(zend_class_entry *entry, zval *obje * @param tsrm_ls * @return int */ -int ClassImpl::serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) +int ClassImpl::serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data TSRMLS_DC) { // get the serializable object Serializable *serializable = dynamic_cast<Serializable*>(ObjectImpl::find(object TSRMLS_CC)->object()); @@ -1328,13 +1279,13 @@ int ClassImpl::serialize(zval *object, unsigned char **buffer, zend_uint *buf_le * @param tsrm_ls * @return int */ -int ClassImpl::unserialize(zval **object, zend_class_entry *entry, const unsigned char *buffer, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC) +int ClassImpl::unserialize(zval *object, zend_class_entry *entry, const unsigned char *buffer, size_t buf_len, zend_unserialize_data *data TSRMLS_DC) { // create the PHP object - object_init_ex(*object, entry); + object_init_ex(object, entry); // turn this into a serializale - Serializable *serializable = dynamic_cast<Serializable*>(ObjectImpl::find(*object TSRMLS_CC)->object()); + Serializable *serializable = dynamic_cast<Serializable*>(ObjectImpl::find(object TSRMLS_CC)->object()); // user may throw an exception in the serialize() function try @@ -1390,7 +1341,7 @@ const struct _zend_function_entry *ClassImpl::entries() zend_function_entry *last = &_entries[i]; // all should be set to zero - memset(last, 0, sizeof(zend_function_entry)); + memset(last, 0, sizeof(*last)); // done return _entries; @@ -1448,7 +1399,7 @@ zend_class_entry *ClassImpl::initialize(ClassBase *base, const std::string &pref if (_parent->_entry) { // register the class - _entry = zend_register_internal_class_ex(&entry, _parent->_entry, const_cast<char*>(_parent->name().c_str()) TSRMLS_CC); + _entry = zend_register_internal_class_ex(&entry, _parent->_entry TSRMLS_CC); } else { @@ -1478,29 +1429,15 @@ zend_class_entry *ClassImpl::initialize(ClassBase *base, const std::string &pref // this pointer has to be copied to temporary pointer, as &this causes compiler error ClassImpl *impl = this; -#if PHP_VERSION_ID >= 50400 - - // allocate doc comment to contain an empty string + a hidden pointer - _self = (char *)malloc(1 + sizeof(ClassImpl *)); - - // empty string on first position - _self[0] = '\0'; - - // copy the 'this' pointer to the doc-comment - memcpy(_self+1, &impl, sizeof(ClassImpl *)); - - // set our comment in the actual class entry - _entry->info.user.doc_comment = _self; - -#else - - // Reallocate some extra space in the name in the zend_class_entry so we can fit a pointer behind it - _entry->name = (char *) realloc(_entry->name, _entry->name_length + 1 + sizeof(ClassImpl *)); + // allocate memory for the doc_comment (which we abuse for storing a pointer to ourselves) + _self = zend_string_alloc(sizeof(this), 1); - // Copy the pointer after it - memcpy(_entry->name + _entry->name_length + 1, &impl, sizeof(ClassImpl *)); + // make the string appear empty + ZSTR_VAL(_self)[0] = '\0'; + ZSTR_LEN(_self) = 0; -#endif + // copy over the 'this'-pointer after the null-character + std::memcpy(ZSTR_VAL(_self) + 1, &impl, sizeof(impl)); // set access types flags for class _entry->ce_flags = (int)_type; |