summaryrefslogtreecommitdiff
path: root/zend/objectimpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'zend/objectimpl.h')
-rw-r--r--zend/objectimpl.h123
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;
- }
};
/**