From ffdaa0590d33ea89d116f6c56df2474cc0675ec9 Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Wed, 25 Sep 2013 14:59:58 -0700 Subject: {auto} PHP objects can now be implemented in C++. Constructors and destructors get called at the appropriate time, but not yet any of the other methods --- src/classinfo.cpp | 153 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 130 insertions(+), 23 deletions(-) (limited to 'src/classinfo.cpp') diff --git a/src/classinfo.cpp b/src/classinfo.cpp index 760df5c..7de7522 100644 --- a/src/classinfo.cpp +++ b/src/classinfo.cpp @@ -13,41 +13,147 @@ namespace Php { /** - * Function that is called by the Zend engine every time that a function gets called + * Structure that combines a C++ object with a zend object + */ +struct MixedObject +{ + zend_object php; + Base *cpp; +}; + +/** + * Function that is called to clean up space that is occupied by the object + * @param object The object to be deallocated + */ +static void deallocate_object(void *object TSRMLS_DC) +{ + // allocate memory for the object + MixedObject *obj = (MixedObject *)object; + + // deallocate the cpp object + if (obj->cpp) delete obj->cpp; + + // get rid of the object properties + zend_hash_destroy(obj->php.properties); + FREE_HASHTABLE(obj->php.properties); + + // deallocate the entire object + efree(obj); +} + +/** + * Function that is called to create space for a cloned object + * @param object The object to be cloned + * @param clone The address that should become the clone + */ +static void clone_object(void *object, void **clone TSRMLS_DC) +{ + std::cout << "clone_object" << std::endl; + + // @todo implementation +} + +/** + * Function that is called when an instance of the class needs to be created. + * This function will create the C++ class, and the PHP object + * @param type Pointer to the class + */ +static zend_object_value create_object(zend_class_entry *type TSRMLS_DC) +{ + // allocate memory for the object + MixedObject *object = (MixedObject *)emalloc(sizeof(MixedObject)); + + // retrieve the classinfo object + _ClassInfo *info = (_ClassInfo *)type->info.user.doc_comment; + + // construct the cpp object + object->cpp = info->construct(); + + // store the class + object->php.ce = type; + + // the original create_object fills the initial object with the default properties, + // we're going to do exactly the same. start with setting up a hashtable for the props + ALLOC_HASHTABLE(object->php.properties); + + // initialize the hash table + zend_hash_init(object->php.properties, 0, NULL, ZVAL_PTR_DTOR, 0); + + // initialize the properties + object_properties_init(&(object->php), type); + + // the thing we're going to return + zend_object_value result; + + // use default object handlers + result.handlers = zend_get_std_object_handlers(); + + // put the object in the storage, and assign a method for deallocating and cloning + result.handle = zend_objects_store_put(object, NULL, deallocate_object, clone_object TSRMLS_CC); + + // done + return result; +} + +/** + * Function that is called by the Zend engine every time the constructor gets called * @param ht * @param return_value * @param return_value_ptr * @param this_ptr * @param return_value_used * @param tsrm_ls - * @return integer */ -void invoke_method(INTERNAL_FUNCTION_PARAMETERS) +static void invoke_constructor(INTERNAL_FUNCTION_PARAMETERS) { - std::cout << "invoke method" << std::endl; - - return; - - // find the function name - const char *name = get_active_function_name(TSRMLS_C); - - // uncover the hidden pointer inside the function name - Function *function = HiddenPointer(name); - - // wrap the return value - Value result(return_value, true); + // get the mixed object + MixedObject *obj = (MixedObject *)zend_object_store_get_object(this_ptr TSRMLS_CC); // construct parameters Parameters params(ZEND_NUM_ARGS()); - // get the result - result = function->invoke(*PHPCPP_G(environment), params); + // call the constructor + obj->cpp->__construct(*PHPCPP_G(environment), params); +} + +/** + * Function that is called by the Zend engine every time the destructor gets called + * @param ht + * @param return_value + * @param return_value_ptr + * @param this_ptr + * @param return_value_used + * @param tsrm_ls + */ +static void invoke_destructor(INTERNAL_FUNCTION_PARAMETERS) +{ + // get the mixed object + MixedObject *obj = (MixedObject *)zend_object_store_get_object(this_ptr TSRMLS_CC); + + // call the destructor + obj->cpp->__destruct(*PHPCPP_G(environment)); } /** - * Helper struct to create an internal method + * Constructor + * @param name */ +_ClassInfo::_ClassInfo(const char *name) : _name(name), _entry(NULL) +{ + // allocate internal functions + _constructor = new InternalFunction(invoke_constructor, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR); + _destructor = new InternalFunction(invoke_destructor, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR); +} +/** + * Destructor + */ +_ClassInfo::~_ClassInfo() +{ + // deallocate internal function + delete _constructor; + delete _destructor; +} /** * Initialize the class @@ -61,15 +167,16 @@ void _ClassInfo::initialize(TSRMLS_D) // initialize the class entry INIT_CLASS_ENTRY_EX(entry, _name.c_str(), _name.size(), NULL); - // functions we need - // @todo should not be static - static InternalFunction constructor(invoke_method, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC); - // we need a special constructor - entry.__call = constructor; + entry.create_object = create_object; + entry.constructor = _constructor->function(); + entry.destructor = _destructor->function(); // register the class _entry = zend_register_internal_class(&entry TSRMLS_CC); + + // store pointer to the class in the unused doc_comment member + _entry->info.user.doc_comment = (const char *)this; } /** -- cgit v1.2.3