diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-04-06 19:48:30 +0200 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-04-06 19:48:30 +0200 |
commit | 5e18247595e73491796ebeb2e3ac5f2e8af5042b (patch) | |
tree | 8af5b978c73384b67e32a1daee21c03c4174d95b | |
parent | 9bc5d1ed595e0ff0b7cec9a87d06a7923c211ebd (diff) |
refactored code, so that there is no zend engine dependency left in base.h header file
-rw-r--r-- | include/base.h | 42 | ||||
-rw-r--r-- | src/base.cpp | 110 | ||||
-rw-r--r-- | src/classimpl.cpp | 157 | ||||
-rw-r--r-- | src/classimpl.h | 7 | ||||
-rw-r--r-- | src/includes.h | 2 | ||||
-rw-r--r-- | src/mixedobject.h | 39 | ||||
-rw-r--r-- | src/object.cpp | 7 | ||||
-rw-r--r-- | src/objectimpl.h | 204 | ||||
-rw-r--r-- | src/parameters.cpp | 5 | ||||
-rw-r--r-- | src/value.cpp | 16 |
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(); } /** |