diff options
Diffstat (limited to 'zend/objectimpl.h')
-rw-r--r-- | zend/objectimpl.h | 123 |
1 files changed, 39 insertions, 84 deletions
diff --git a/zend/objectimpl.h b/zend/objectimpl.h index 110491b..b014bb1 100644 --- a/zend/objectimpl.h +++ b/zend/objectimpl.h @@ -27,32 +27,25 @@ private: struct MixedObject { /** - * The actual object is the first member, so that casting - * the MixedObject to a zend_object will also result in a valid pointer - * @var zend_object - */ - zend_object php; - - /** * Pointer to ourselves * @var ObjectImpl */ ObjectImpl *self; + /** + * The actual object MUST be the last member, because PHP uses hackish + * tricks for optimization (we allocate more memory than sizeof(MixedObject)) + * @var zend_object + */ + zend_object php; } *_mixed; /** * Pointer to the C++ implementation - * @var Base + * @var std::unique_ptr<Base> */ - Base *_object; - - /** - * The object handle in the Zend engine - * @var int - */ - int _handle; + std::unique_ptr<Base> _object; public: /** @@ -61,65 +54,30 @@ public: * This will create a new object in the Zend engine. * * @param entry Zend class entry + * @param handler Zend object handlers * @param base C++ object that already exists * @param refcount The initial refcount for the object * @param tsrm_ls Optional threading data */ - ObjectImpl(zend_class_entry *entry, Base *base, int refcount TSRMLS_DC) + ObjectImpl(zend_class_entry *entry, Base *base, zend_object_handlers *handlers, int refcount TSRMLS_DC) : + _object(base) { // allocate a mixed object (for some reason this does not have to be deallocated) - _mixed = (MixedObject *)emalloc(sizeof(MixedObject)); + _mixed = (MixedObject *)ecalloc(1, sizeof(MixedObject) + zend_object_properties_size(entry)); // copy properties to the mixed object _mixed->php.ce = entry; _mixed->self = this; - // store the c++ object - _object = base; - - // initialize the object - zend_object_std_init(&_mixed->php, entry TSRMLS_CC); - -#if PHP_VERSION_ID < 50399 - - // tmp variable - zval *tmp; - - // initialize the properties, php 5.3 way - zend_hash_copy(_mixed->php.properties, &entry->default_properties, (copy_ctor_func_t) zval_property_ctor, &tmp, sizeof(zval*)); - -#else - - // version higher than 5.3 have an easier way to initialize + // initialize the object and its properties + zend_object_std_init (&_mixed->php, entry TSRMLS_CC); object_properties_init(&_mixed->php, entry); -#endif - -#ifdef ZTS - - // when in thread safety mode, the destruct method and free method have - // an extra parameter holding thread information - using DestructType = void(*)(zend_object*,unsigned int,void***); - using FreeType = void(*)(zend_object*,void***); - -#else - - // not in thread mode: no special parameter for the tsrm_ls variable - using DestructType = void(*)(zend_object*, unsigned int); - using FreeType = void(*)(zend_object*); - -#endif - - // store the two destruct methods in temporary vars - DestructType destructMethod = &ClassImpl::destructObject; - FreeType freeMethod = &ClassImpl::freeObject; - - // the destructor and clone handlers are set to NULL. I dont know why, but they do not - // seem to be necessary... - _handle = zend_objects_store_put(php(), (zend_objects_store_dtor_t)destructMethod, (zend_objects_free_object_storage_t)freeMethod, NULL TSRMLS_CC); + // install the handlers + _mixed->php.handlers = handlers; // set the initial refcount (if it is different than one, because one is the default) - if (refcount != 1) EG(objects_store).object_buckets[_handle].bucket.obj.refcount = refcount; + if (refcount != 1) php()->gc.refcount = refcount; // the object may remember that we are its implementation object base->_impl = this; @@ -128,11 +86,7 @@ public: /** * Destructor */ - virtual ~ObjectImpl() - { - // deallocate the cpp object - if (_object) delete _object; - } + virtual ~ObjectImpl() = default; /** * Destruct the object @@ -140,14 +94,24 @@ public: */ void destruct(TSRMLS_D) { - // pass on to the default destructor - zend_objects_free_object_storage(php() TSRMLS_CC); - // destruct the object delete this; } /** + * The offset between the zend_object and the ObjectImpl + * in bytes. This can be used to find the other when only + * a pointer to one is available. + * + * @return The offset in bytes + */ + static constexpr size_t offset() + { + // calculate the offset in bytes + return offsetof(MixedObject, php); + } + + /** * Find the object based on a zval * @param val Zval object * @param tsrm_ls Optional pointer to thread info @@ -155,11 +119,8 @@ public: */ static ObjectImpl *find(zval *val TSRMLS_DC) { - // retrieve the old object, which we are going to copy - MixedObject *object = (MixedObject *)zend_object_store_get_object(val TSRMLS_CC); - - // done - return object->self; + // retrieve the zend_object from the zval and use it to find the ObjectImpl + return find(Z_OBJ_P(val)); } /** @@ -169,8 +130,11 @@ public: */ static ObjectImpl *find(const zend_object *object) { - // retrieve the old object, which we are going to copy - const MixedObject *mixed = (const MixedObject *)object; + // the zend_object is the last pointer in the struct so we have to subtract the + // correct number of bytes from the pointer to get at the address at which the + // actual ObjectImpl starts. to be able to actually perform this pointer arithmetic + // we must first cast the pointer to a char (void pointer arithmetic is not allowed!) + auto *mixed = (const MixedObject*)((char*)object - offset()); // done return mixed->self; @@ -182,7 +146,7 @@ public: */ Base *object() const { - return _object; + return _object.get(); } /** @@ -193,15 +157,6 @@ public: { return &_mixed->php; } - - /** - * Retrieve the handle object - * @return int - */ - int handle() const - { - return _handle; - } }; /** |