summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-04-06 19:48:30 +0200
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-04-06 19:48:30 +0200
commit5e18247595e73491796ebeb2e3ac5f2e8af5042b (patch)
tree8af5b978c73384b67e32a1daee21c03c4174d95b
parent9bc5d1ed595e0ff0b7cec9a87d06a7923c211ebd (diff)
refactored code, so that there is no zend engine dependency left in base.h header file
-rw-r--r--include/base.h42
-rw-r--r--src/base.cpp110
-rw-r--r--src/classimpl.cpp157
-rw-r--r--src/classimpl.h7
-rw-r--r--src/includes.h2
-rw-r--r--src/mixedobject.h39
-rw-r--r--src/object.cpp7
-rw-r--r--src/objectimpl.h204
-rw-r--r--src/parameters.cpp5
-rw-r--r--src/value.cpp16
10 files changed, 353 insertions, 236 deletions
diff --git a/include/base.h b/include/base.h
index 8b3e561..87c7483 100644
--- a/include/base.h
+++ b/include/base.h
@@ -13,13 +13,21 @@ namespace Php {
/**
* Forward declarations
*/
-struct MixedObject;
+class ObjectImpl;
+
/**
* Class definition
*/
class Base
{
+private:
+ /**
+ * Object handle in the PHP engine
+ * @var ObjectImpl
+ */
+ ObjectImpl *_impl = nullptr;
+
protected:
/**
* Constructor
@@ -241,41 +249,25 @@ public:
*/
int __compare(const Base &base) const;
-
-private:
- /**
- * Store the object in the zend object cache
- * @param entry
- * @param tsrm_ls
- * @return MixedObject
- */
- MixedObject *store(struct _zend_class_entry *entry TSRMLS_DC);
+private:
/**
- * Retrieve the handle
- * @return int
+ * Get access to the implementation object
+ * @return ObjectImpl
*/
- int handle() const
+ const ObjectImpl *implementation() const
{
- return _handle;
+ return _impl;
}
-
- /**
- * The handle in the zend object cache
- * @var int
- */
- int _handle = 0;
/**
- * Friends that have access to the private members
+ * Classes that have direct access to private date
*/
- friend class Value;
+ friend class ObjectImpl;
friend class Object;
- friend class ClassImpl;
-
+ friend class Value;
};
-
/**
* End of namespace
*/
diff --git a/src/base.cpp b/src/base.cpp
index a828083..5d15011 100644
--- a/src/base.cpp
+++ b/src/base.cpp
@@ -18,61 +18,61 @@ namespace Php {
* @param tsrm_ls
* @return MixedObject
*/
-MixedObject *Base::store(zend_class_entry *entry TSRMLS_DC)
-{
- // allocate memory for the object
- MixedObject *result = (MixedObject *)emalloc(sizeof(MixedObject));
-
- // store the new c++ object
- result->cpp = this;
-
- // store the class entry in the newly created object
- result->php.ce = entry;
-
- // initialize the object
- zend_object_std_init(&result->php, entry TSRMLS_CC);
-
-#if PHP_VERSION_ID < 50399
-
- // tmp variable
- zval *tmp;
-
- // initialize the properties, php 5.3 way
- zend_hash_copy(result->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
- object_properties_init(&result->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(result, (zend_objects_store_dtor_t)destructMethod, (zend_objects_free_object_storage_t)freeMethod, NULL TSRMLS_CC);
-
- // done
- return result;
-}
+//MixedObject *Base::store(zend_class_entry *entry TSRMLS_DC)
+//{
+// // allocate memory for the object
+// MixedObject *result = (MixedObject *)emalloc(sizeof(MixedObject));
+//
+// // store the new c++ object
+// result->cpp = this;
+//
+// // store the class entry in the newly created object
+// result->php.ce = entry;
+//
+// // initialize the object
+// zend_object_std_init(&result->php, entry TSRMLS_CC);
+//
+//#if PHP_VERSION_ID < 50399
+//
+// // tmp variable
+// zval *tmp;
+//
+// // initialize the properties, php 5.3 way
+// zend_hash_copy(result->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
+// object_properties_init(&result->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(result, (zend_objects_store_dtor_t)destructMethod, (zend_objects_free_object_storage_t)freeMethod, NULL TSRMLS_CC);
+//
+// // done
+// return result;
+//}
/**
* Overridable method that is called right before an object is destructed
diff --git a/src/classimpl.cpp b/src/classimpl.cpp
index ea7fdd7..84b43df 100644
--- a/src/classimpl.cpp
+++ b/src/classimpl.cpp
@@ -28,11 +28,15 @@ ClassImpl::~ClassImpl()
}
/**
+ * @todo refactor so that methods become simpler
+ */
+
+/**
* Retrieve our C++ implementation object
* @param entry
* @return ClassImpl
*/
-static ClassImpl *cpp_impl(zend_class_entry *entry)
+static ClassImpl *self(zend_class_entry *entry)
{
// we need the base class (in user space the class may have been overridden,
// but we are not interested in these user space classes)
@@ -52,34 +56,6 @@ static ClassImpl *cpp_impl(zend_class_entry *entry)
}
/**
- * Retrieve the extension's class object
- * @param entry
- * @return ClassBase
- */
-ClassBase *ClassImpl::base(zend_class_entry *entry)
-{
- // first the implementation class
- ClassImpl *impl = cpp_impl(entry);
-
- // and now the base
- return impl->_base;
-}
-
-/**
- * Retrieve the CPP object
- * @param val
- * @return Base
- */
-static Base *cpp_object(const 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);
-
- // return the cpp object
- return object->cpp;
-}
-
-/**
* Extended zend_internal_function structure that we use to store an
* instance of the ClassBase object. We need this for static method calls
*/
@@ -244,7 +220,7 @@ zend_function *ClassImpl::getMethod(zval **object_ptr, char *method_name, int me
function->function_name = method_name;
// store pointer to ourselves
- data->self = cpp_impl(entry);
+ data->self = self(entry);
// done (cast to zend_function* is allowed, because a zend_function is a union
// that has one member being a zend_internal_function)
@@ -289,7 +265,7 @@ zend_function *ClassImpl::getStaticMethod(zend_class_entry *entry, char* method,
function->function_name = method;
// store pointer to ourselves
- data->self = cpp_impl(entry);
+ data->self = self(entry);
// done (cast to zend_function* is allowed, because a zend_function is a union
// that has one member being a zend_internal_function)
@@ -334,7 +310,7 @@ int ClassImpl::getClosure(zval *object, zend_class_entry **entry_ptr, zend_funct
function->function_name = nullptr;
// store pointer to ourselves
- data->self = cpp_impl(entry);
+ data->self = self(entry);
// assign this dynamically allocated variable to the func parameter
// the case is ok, because zend_internal_function is a member of the
@@ -405,31 +381,31 @@ zend_object_handlers *ClassImpl::objectHandlers()
/**
* Function to compare two objects
- * @param object1
- * @param object2
+ * @param val1
+ * @param val2
* @param tsrm_ls
* @return int
*/
-int ClassImpl::compare(zval *object1, zval *object2 TSRMLS_DC)
+int ClassImpl::compare(zval *val1, zval *val2 TSRMLS_DC)
{
// prevent exceptions
try
{
// retrieve the class entry linked to this object
- auto *entry = zend_get_class_entry(object1 TSRMLS_CC);
+ auto *entry = zend_get_class_entry(val1 TSRMLS_CC);
// other object must be of the same type
- if (entry != zend_get_class_entry(object2 TSRMLS_CC)) throw NotImplemented();
+ if (entry != zend_get_class_entry(val2 TSRMLS_CC)) throw NotImplemented();
// we need the C++ class meta-information object
- ClassBase *meta = base(entry);
+ ClassBase *meta = self(entry)->_base;
// get the base objects
- Base *base1 = cpp_object(object1 TSRMLS_CC);
- Base *base2 = cpp_object(object2 TSRMLS_CC);
+ Base *object1 = ObjectImpl::find(val1 TSRMLS_CC)->object();
+ Base *object2 = ObjectImpl::find(val2 TSRMLS_CC)->object();
// run the compare method
- return meta->callCompare(base1, base2);
+ return meta->callCompare(object1, object2);
}
catch (const NotImplemented &exception)
{
@@ -437,7 +413,7 @@ int ClassImpl::compare(zval *object1, zval *object2 TSRMLS_DC)
if (!std_object_handlers.compare_objects) return 1;
// call default
- return std_object_handlers.compare_objects(object1, object2 TSRMLS_CC);
+ return std_object_handlers.compare_objects(val1, val2 TSRMLS_CC);
}
catch (Exception &exception)
{
@@ -452,22 +428,22 @@ int ClassImpl::compare(zval *object1, zval *object2 TSRMLS_DC)
/**
* Function to cast the object to a different type
- * @param object
+ * @param val
* @param retval
* @param type
* @param tsrm_ls
* @return int
*/
-int ClassImpl::cast(zval *object, zval *retval, int type TSRMLS_DC)
+int ClassImpl::cast(zval *val, zval *retval, int type TSRMLS_DC)
{
- // get the base object
- Base *base = cpp_object(object TSRMLS_CC);
+ // get the base c++ object
+ Base *object = ObjectImpl::find(val TSRMLS_CC)->object();
// retrieve the class entry linked to this object
- auto *entry = zend_get_class_entry(object TSRMLS_CC);
+ auto *entry = zend_get_class_entry(val TSRMLS_CC);
// we need the C++ class meta-information object
- ClassBase *meta = ClassImpl::base(entry);
+ ClassBase *meta = self(entry)->_base;
// retval it not yet initialized --- and again feelings of disbelief,
// frustration, wonder and anger come up when you see that there are not two
@@ -486,18 +462,18 @@ int ClassImpl::cast(zval *object, zval *retval, int type TSRMLS_DC)
// check type
switch ((Type)type) {
- case Type::Numeric: result = meta->callToInteger(base).detach(); break;
- case Type::Float: result = meta->callToFloat(base).detach(); break;
- case Type::Bool: result = meta->callToBool(base).detach(); break;
- case Type::String: result = meta->callToString(base).detach(); break;
+ case Type::Numeric: result = meta->callToInteger(object).detach(); break;
+ case Type::Float: result = meta->callToFloat(object).detach(); break;
+ case Type::Bool: result = meta->callToBool(object).detach(); break;
+ case Type::String: result = meta->callToString(object).detach(); break;
default: throw NotImplemented(); break;
}
// @todo do we turn into endless conversion if the __toString object returns 'this' ??
// (and if it does: who cares? If the extension programmer is stupid, why do we have to suffer?)
- // is the object overwritten?
- if (object == retval) zval_dtor(object);
+ // is the original parameter overwritten?
+ if (val == retval) zval_dtor(val);
// overwrite the result
ZVAL_ZVAL(retval, result, 1, 1);
@@ -511,7 +487,7 @@ int ClassImpl::cast(zval *object, zval *retval, int type TSRMLS_DC)
if (!std_object_handlers.cast_object) return FAILURE;
// call default
- return std_object_handlers.cast_object(object, retval, type TSRMLS_CC);
+ return std_object_handlers.cast_object(val, retval, type TSRMLS_CC);
}
catch (Exception &exception)
{
@@ -534,14 +510,14 @@ zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC)
auto *entry = zend_get_class_entry(val TSRMLS_CC);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
ClassBase *meta = impl->_base;
// retrieve the old object, which we are going to copy
- MixedObject *old_object = (MixedObject *)zend_object_store_get_object(val TSRMLS_CC);
+ ObjectImpl *old_object = ObjectImpl::find(val TSRMLS_CC);
// create a new base c++ object
- auto *cpp = meta->clone(old_object->cpp);
+ auto *cpp = meta->clone(old_object->object());
// report error on failure (this does not occur because the cloneObject()
// method is only installed as handler when we have seen that there is indeed
@@ -555,14 +531,14 @@ zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC)
result.handlers = impl->objectHandlers();
// store the object
- MixedObject *new_object = cpp->store(entry TSRMLS_CC);
+ ObjectImpl *new_object = new ObjectImpl(entry, cpp TSRMLS_CC);
// store the object in the object cache
- result.handle = cpp->handle();
+ result.handle = new_object->handle();
// 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(), result, old_object->php(), Z_OBJ_HANDLE_P(val) TSRMLS_CC);
// was a custom clone method installed? If not we call the magic c++ __clone method
if (!entry->clone) meta->callClone(cpp);
@@ -584,7 +560,7 @@ zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC)
int ClassImpl::countElements(zval *object, long *count TSRMLS_DC)
{
// does it implement the countable interface?
- Countable *countable = dynamic_cast<Countable*>(cpp_object(object TSRMLS_CC));
+ Countable *countable = dynamic_cast<Countable*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the Countable interface, we rely on the default implementation
if (countable)
@@ -650,7 +626,7 @@ zval *ClassImpl::readDimension(zval *object, zval *offset, int type TSRMLS_DC)
// does it implement the arrayaccess interface?
- ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(cpp_object(object TSRMLS_CC));
+ ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the ArrayAccess interface, we rely on the default implementation
if (arrayaccess)
@@ -695,7 +671,7 @@ zval *ClassImpl::readDimension(zval *object, zval *offset, int type TSRMLS_DC)
void ClassImpl::writeDimension(zval *object, zval *offset, zval *value TSRMLS_DC)
{
// does it implement the arrayaccess interface?
- ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(cpp_object(object TSRMLS_CC));
+ ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the ArrayAccess interface, we rely on the default implementation
if (arrayaccess)
@@ -737,7 +713,7 @@ void ClassImpl::writeDimension(zval *object, zval *offset, zval *value TSRMLS_DC
int ClassImpl::hasDimension(zval *object, zval *member, int check_empty TSRMLS_DC)
{
// does it implement the arrayaccess interface?
- ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(cpp_object(object TSRMLS_CC));
+ ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the ArrayAccess interface, we rely on the default implementation
if (arrayaccess)
@@ -787,7 +763,7 @@ int ClassImpl::hasDimension(zval *object, zval *member, int check_empty TSRMLS_D
void ClassImpl::unsetDimension(zval *object, zval *member TSRMLS_DC)
{
// does it implement the arrayaccess interface?
- ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(cpp_object(object TSRMLS_CC));
+ ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the ArrayAccess interface, we rely on the default implementation
if (arrayaccess)
@@ -871,13 +847,13 @@ zval *ClassImpl::readProperty(zval *object, zval *name, int type, const zend_lit
// that is in most cases simply impossible.
// retrieve the object and class
- Base *base = cpp_object(object TSRMLS_CC);
+ 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);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
ClassBase *meta = impl->_base;
// the default implementation throws an exception, so by catching
@@ -945,13 +921,13 @@ void ClassImpl::writeProperty(zval *object, zval *name, zval *value, const zend_
#endif
{
// retrieve the object and class
- Base *base = cpp_object(object TSRMLS_CC);
+ 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);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
ClassBase *meta = impl->_base;
// the default implementation throws an exception, if we catch that
@@ -1030,13 +1006,13 @@ int ClassImpl::hasProperty(zval *object, zval *name, int has_set_exists, const z
try
{
// get the cpp object
- Base *base = cpp_object(object TSRMLS_CC);
+ 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);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
ClassBase *meta = impl->_base;
// convert the name to a Value object
@@ -1107,7 +1083,7 @@ void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *ke
auto *entry = zend_get_class_entry(object TSRMLS_CC);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
// property name
Value name(member);
@@ -1116,7 +1092,7 @@ void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *ke
auto iter = impl->_properties.find(name);
// if the property does not exist, we forward to the __unset
- if (iter == impl->_properties.end()) impl->_base->callUnset(cpp_object(object TSRMLS_CC), member);
+ if (iter == impl->_properties.end()) impl->_base->callUnset(ObjectImpl::find(object TSRMLS_CC)->object(), member);
// callback properties cannot be unset
zend_error(E_ERROR, "Property %s can not be unset", (const char *)name);
@@ -1150,17 +1126,17 @@ void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *ke
*/
void ClassImpl::destructObject(zend_object *object, zend_object_handle handle TSRMLS_DC)
{
- // allocate memory for the object
- MixedObject *obj = (MixedObject *)object;
+ // find object
+ ObjectImpl *obj = ObjectImpl::find(object);
// get meta info
- ClassImpl *impl = cpp_impl(object->ce);
+ ClassImpl *impl = self(object->ce);
// prevent exceptions
try
{
// call the destruct function
- if (obj->cpp) impl->_base->callDestruct(obj->cpp);
+ if (obj->object()) impl->_base->callDestruct(obj->object());
}
catch (const NotImplemented &exception)
{
@@ -1183,13 +1159,10 @@ void ClassImpl::destructObject(zend_object *object, zend_object_handle handle TS
void ClassImpl::freeObject(zend_object *object TSRMLS_DC)
{
// allocate memory for the object
- MixedObject *obj = (MixedObject *)object;
-
- // deallocate the cpp object
- if (obj->cpp) delete obj->cpp;
+ ObjectImpl *obj = ObjectImpl::find(object);
- // pass on to the default destructor
- zend_objects_free_object_storage(object TSRMLS_CC);
+ // no longer need it
+ obj->destruct(TSRMLS_CC);
}
/**
@@ -1202,7 +1175,7 @@ void ClassImpl::freeObject(zend_object *object TSRMLS_DC)
zend_object_value ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC)
{
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
// create a new base C++ object
auto *cpp = impl->_base->construct();
@@ -1216,11 +1189,11 @@ zend_object_value ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC)
// set the handlers
result.handlers = impl->objectHandlers();
- // store the object
- cpp->store(entry TSRMLS_CC);
-
+ // create the object in the zend engine
+ ObjectImpl *object = new ObjectImpl(entry, cpp TSRMLS_CC);
+
// store the object in the object cache
- result.handle = cpp->handle();
+ result.handle = object->handle();
// done
return result;
@@ -1240,7 +1213,7 @@ zend_object_iterator *ClassImpl::getIterator(zend_class_entry *entry, zval *obje
if (by_ref) throw Php::Exception("Foreach by ref is not possible");
// retrieve the traversable object
- Traversable *traversable = dynamic_cast<Traversable*>(cpp_object(object TSRMLS_CC));
+ Traversable *traversable = dynamic_cast<Traversable*>(ObjectImpl::find(object TSRMLS_CC)->object());
// user may throw an exception in the getIterator() function
try
@@ -1274,7 +1247,7 @@ zend_object_iterator *ClassImpl::getIterator(zend_class_entry *entry, zval *obje
int ClassImpl::serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC)
{
// get the serializable object
- Serializable *serializable = dynamic_cast<Serializable*>(cpp_object(object TSRMLS_CC));
+ Serializable *serializable = dynamic_cast<Serializable*>(ObjectImpl::find(object TSRMLS_CC)->object());
// call the serialize method on the object
auto value = serializable->serialize();
@@ -1304,7 +1277,7 @@ int ClassImpl::unserialize(zval **object, zend_class_entry *entry, const unsigne
object_init_ex(*object, entry);
// turn this into a serializale
- Serializable *serializable = dynamic_cast<Serializable*>(cpp_object(*object TSRMLS_CC));
+ Serializable *serializable = dynamic_cast<Serializable*>(ObjectImpl::find(*object TSRMLS_CC)->object());
// call the unserialize method on it
serializable->unserialize((const char *)buffer, buf_len);
diff --git a/src/classimpl.h b/src/classimpl.h
index cf28199..febdbca 100644
--- a/src/classimpl.h
+++ b/src/classimpl.h
@@ -134,13 +134,6 @@ public:
}
/**
- * Retrieve the extension's class object
- * @param entry
- * @return ClassBase
- */
- static ClassBase *base(zend_class_entry *entry);
-
- /**
* Initialize the class, given its name
*
* The module functions are registered on module startup, but classes are
diff --git a/src/includes.h b/src/includes.h
index 48df910..672cef1 100644
--- a/src/includes.h
+++ b/src/includes.h
@@ -79,7 +79,6 @@
/**
* Interface files for internal use only
*/
-#include "mixedobject.h"
#include "callable.h"
#include "function.h"
#include "method.h"
@@ -100,6 +99,7 @@
#include "iteratorimpl.h"
#include "streambuf.h"
#include "classimpl.h"
+#include "objectimpl.h"
#include "extensionimpl.h"
#ifndef ZVAL_COPY_VALUE
diff --git a/src/mixedobject.h b/src/mixedobject.h
deleted file mode 100644
index 4db74da..0000000
--- a/src/mixedobject.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * MixedObject.h
- *
- * Structure that combines a Zend object with an object in C++
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
- */
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Structure that combines a C++ object with a zend object
- */
-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 the C++ implementation
- * @var Base
- */
- Base *cpp;
-};
-
-/**
- * End of namespace
- */
-}
-
-
diff --git a/src/object.cpp b/src/object.cpp
index 05449bc..d7fc158 100644
--- a/src/object.cpp
+++ b/src/object.cpp
@@ -20,7 +20,7 @@ namespace Php {
Object::Object(const char *name, Base *base)
{
// does the object already have a handle?
- if (base->handle())
+ if (base->implementation())
{
// the object is already instantiated, we can assign it the this object
operator=(Value(base));
@@ -36,8 +36,9 @@ Object::Object(const char *name, Base *base)
auto *entry = zend_fetch_class(name, strlen(name), 0 TSRMLS_CC);
if (!entry) throw Php::Exception(std::string("Unknown class name ") + name);
- // store the object in the php object cache (this will give the object a handle)
- base->store(entry TSRMLS_CC);
+ // construct an implementation (this will also set the implementation
+ // member in the base object)
+ new ObjectImpl(entry, base TSRMLS_CC);
// now we can store it
operator=(Value(base));
diff --git a/src/objectimpl.h b/src/objectimpl.h
new file mode 100644
index 0000000..41bed53
--- /dev/null
+++ b/src/objectimpl.h
@@ -0,0 +1,204 @@
+/**
+ * ObjectImpl.h
+ *
+ * Implementation class for Base objects that allow the objects to be stored
+ * in the Zend engine
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class ObjectImpl
+{
+private:
+ /**
+ * Structure with a first element which is a mixed object, so that
+ * it can be casted to a zend_object
+ * @var MixedObject
+ */
+ 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;
+
+
+ } _mixed;
+
+ /**
+ * Pointer to the C++ implementation
+ * @var Base
+ */
+ Base *_object;
+
+ /**
+ * The object handle in the Zend engine
+ * @var int
+ */
+ int _handle;
+
+public:
+ /**
+ * Constructor
+ *
+ * This will create a new object in the Zend engine.
+ *
+ * @param entry Zend class entry
+ * @param base C++ object that already exists
+ * @param tsrm_ls Optional threading data
+ */
+ ObjectImpl(zend_class_entry *entry, Base *base TSRMLS_DC)
+ {
+ // 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
+ 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(&_mixed, (zend_objects_store_dtor_t)destructMethod, (zend_objects_free_object_storage_t)freeMethod, NULL TSRMLS_CC);
+
+ // the object may remember that we are its implementation object
+ base->_impl = this;
+ }
+
+ /**
+ * Destructor
+ */
+ virtual ~ObjectImpl()
+ {
+ // deallocate the cpp object
+ delete _object;
+ }
+
+ /**
+ * Destruct the object
+ * @param tsrm_ls
+ */
+ void destruct(TSRMLS_D)
+ {
+ // pass on to the default destructor
+ zend_objects_free_object_storage(&_mixed.php TSRMLS_CC);
+
+ // destruct the object
+ delete this;
+ }
+
+ /**
+ * Find the object based on a zval
+ * @param val Zval object
+ * @param tsrm_ls Optional pointer to thread info
+ * @return ObjectImpl
+ */
+ 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;
+ }
+
+ /**
+ * Find the object based on a zend_object
+ * @param object Zend object pointer
+ * @return ObjectImpl
+ */
+ static ObjectImpl *find(const zend_object *object)
+ {
+ // retrieve the old object, which we are going to copy
+ const MixedObject *mixed = (MixedObject *)object;
+
+ // done
+ return mixed->self;
+ }
+
+ /**
+ * Retrieve the base class of the original C++ object
+ * @return Base
+ */
+ Base *object()
+ {
+ return _object;
+ }
+
+ /**
+ * Pointer to the PHP object
+ * @return zend_object
+ */
+ zend_object *php()
+ {
+ return &_mixed.php;
+ }
+
+ /**
+ * Retrieve the handle object
+ * @return int
+ */
+ int handle() const
+ {
+ return _handle;
+ }
+};
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/src/parameters.cpp b/src/parameters.cpp
index c4ed9c7..c7b61a0 100644
--- a/src/parameters.cpp
+++ b/src/parameters.cpp
@@ -35,11 +35,8 @@ Parameters::Parameters(zval *this_ptr, int argc TSRMLS_DC)
// skip if there is no this_ptr
if (!this_ptr) return;
- // get the mixed object
- MixedObject *obj = (MixedObject *)zend_object_store_get_object(this_ptr TSRMLS_CC);
-
// store the CPP object
- _object = obj->cpp;
+ _object = ObjectImpl::find(this_ptr TSRMLS_CC)->object();
}
/**
diff --git a/src/value.cpp b/src/value.cpp
index 6684bd0..9addb8c 100644
--- a/src/value.cpp
+++ b/src/value.cpp
@@ -177,22 +177,22 @@ Value::Value(const Base *object)
{
// there are two options: the object was constructed from user space,
// and is already linked to a handle, or it was constructed from C++
- // space, and no handle does yet exist
- int handle = object->handle();
+ // space, and no handle does yet exist, find the implementation object
+ auto *impl = object->implementation();
// do we have a handle?
- if (!handle) throw Php::Exception("Assigning an unassigned object to a variable");
+ if (!impl) throw Php::Exception("Assigning an unassigned object to a variable");
// make a regular zval, and set it to an object
MAKE_STD_ZVAL(_val);
Z_TYPE_P(_val) = IS_OBJECT;
- Z_OBJ_HANDLE_P(_val) = handle;
+ Z_OBJ_HANDLE_P(_val) = impl->handle();
// we need the tsrm_ls variable
TSRMLS_FETCH();
// we have to lookup the object in the object-table
- zend_object_store_bucket *obj_bucket = &EG(objects_store).object_buckets[handle];
+ zend_object_store_bucket *obj_bucket = &EG(objects_store).object_buckets[impl->handle()];
// this is copy-pasted from zend_objects.c - and it is necessary too!
if (!obj_bucket->bucket.obj.handlers) obj_bucket->bucket.obj.handlers = &std_object_handlers;
@@ -1890,11 +1890,7 @@ Base *Value::implementation() const
TSRMLS_FETCH();
// retrieve the mixed object that contains the base
- MixedObject *object = (MixedObject *)zend_object_store_get_object(_val TSRMLS_CC);
- if (!object) return nullptr;
-
- // retrieve the associated C++ class
- return object->cpp;
+ return ObjectImpl::find(_val TSRMLS_CC)->object();
}
/**