diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/classinfo.cpp | 153 | ||||
-rw-r--r-- | src/extension.cpp | 8 | ||||
-rw-r--r-- | src/function.cpp | 40 | ||||
-rw-r--r-- | src/internalfunction.h | 11 | ||||
-rw-r--r-- | src/nativefunction.h | 4 | ||||
-rw-r--r-- | src/value.cpp | 206 |
6 files changed, 260 insertions, 162 deletions
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<Function>(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; } /** diff --git a/src/extension.cpp b/src/extension.cpp index 7f6c9dd..f4cc9ce 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -21,7 +21,7 @@ namespace Php { /** * Pointer to the one and only extension object - * @var Extension + * @var Extension */ static Extension *extension = nullptr; @@ -123,9 +123,9 @@ static int request_shutdown(INIT_FUNC_ARGS) */ Extension::Extension(const char *name, const char *version, request_callback start, request_callback stop) : _start(start), _stop(stop) { - // store extension variable - extension = this; - + // store extension variable + extension = this; + // allocate memory (we allocate this on the heap so that the size of the // entry does not have to be defined in the .h file. We pay a performance // price for this, but we pay this price becuase the design goal of the diff --git a/src/function.cpp b/src/function.cpp index 2afc1be..79117e5 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -37,34 +37,34 @@ void invoke_function(INTERNAL_FUNCTION_PARAMETERS) // construct parameters Parameters params(ZEND_NUM_ARGS()); - // get the result - result = function->invoke(*PHPCPP_G(environment), params); + // get the result + result = function->invoke(*PHPCPP_G(environment), params); } /** * Constructor - * @param name Name of the function + * @param name Name of the function * @param min Min number of arguments * @param max Max number of arguments */ Function::Function(const char *name, const std::initializer_list<Argument> &arguments) : _ptr(this, name) { - // construct vector for arguments - _argc = arguments.size(); - _argv = new zend_arg_info[_argc+1]; - - // counter - int i=1; - - // loop through the arguments - for (auto it = arguments.begin(); it != arguments.end(); it++) - { - // fill the arg info - it->fill(&_argv[i++]); - } - - // @todo find out number of required arguments - _required = _argc; + // construct vector for arguments + _argc = arguments.size(); + _argv = new zend_arg_info[_argc+1]; + + // counter + int i=1; + + // loop through the arguments + for (auto it = arguments.begin(); it != arguments.end(); it++) + { + // fill the arg info + it->fill(&_argv[i++]); + } + + // @todo find out number of required arguments + _required = _argc; } /** @@ -72,7 +72,7 @@ Function::Function(const char *name, const std::initializer_list<Argument> &argu */ Function::~Function() { - delete[] _argv; + delete[] _argv; } /** diff --git a/src/internalfunction.h b/src/internalfunction.h index 741ea5b..31abcca 100644 --- a/src/internalfunction.h +++ b/src/internalfunction.h @@ -47,19 +47,10 @@ public: virtual ~InternalFunction() {} /** - * Cast to zend_internal_function pointer - * @return zend_internal_function - */ - operator zend_internal_function *() - { - return &_func; - } - - /** * Cast to zend_function pointer * @return zend_function */ - operator zend_function *() + zend_function *function() { return (zend_function *)&_func; } diff --git a/src/nativefunction.h b/src/nativefunction.h index 88d629f..2a61ccb 100644 --- a/src/nativefunction.h +++ b/src/nativefunction.h @@ -21,8 +21,8 @@ class NativeFunction : public Function public: /** * Constructor - * @param name Function name - * @param function The native C function + * @param name Function name + * @param function The native C function */ NativeFunction(const char *name, native_callback_0 function, const std::initializer_list<Argument> &arguments = {}) : Function(name, arguments), _type(0) { _function.f0 = function; } NativeFunction(const char *name, native_callback_1 function, const std::initializer_list<Argument> &arguments = {}) : Function(name, arguments), _type(1) { _function.f1 = function; } diff --git a/src/value.cpp b/src/value.cpp index 5239b33..2a571ab 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -144,9 +144,9 @@ Value::Value(struct _zval_struct *val, bool ref) // we're going to make will not change the other variable if (ref && Z_REFCOUNT_P(_val) > 1) { - // separate the zval - SEPARATE_ZVAL_IF_NOT_REF(&_val); - } + // separate the zval + SEPARATE_ZVAL_IF_NOT_REF(&_val); + } // we see ourselves as reference too Z_ADDREF_P(_val); @@ -216,40 +216,40 @@ Value &Value::operator=(const Value &value) // skip self assignment if (this == &value) return *this; - // is the object a reference? - if (Z_ISREF_P(_val)) - { - // the current object is a reference, this means that we should - // keep the zval object, and copy the other value into it, get - // the current refcount - int refcount = Z_REFCOUNT_P(_val); - - // clean up the current zval (but keep the zval structure) - zval_dtor(_val); - - // make the copy - *_val = *value._val; - zval_copy_ctor(_val); - - // restore refcount and reference setting - Z_SET_ISREF_TO_P(_val, true); - Z_SET_REFCOUNT_P(_val, refcount); - } - else - { - // destruct the zval (this function will decrement the reference counter, - // and only destruct if there are no other references left) - zval_ptr_dtor(&_val); - - // just copy the zval, and the refcounter - _val = value._val; - - // and we have one more reference - Z_ADDREF_P(_val); - } - - // update the object - return *this; + // is the object a reference? + if (Z_ISREF_P(_val)) + { + // the current object is a reference, this means that we should + // keep the zval object, and copy the other value into it, get + // the current refcount + int refcount = Z_REFCOUNT_P(_val); + + // clean up the current zval (but keep the zval structure) + zval_dtor(_val); + + // make the copy + *_val = *value._val; + zval_copy_ctor(_val); + + // restore refcount and reference setting + Z_SET_ISREF_TO_P(_val, true); + Z_SET_REFCOUNT_P(_val, refcount); + } + else + { + // destruct the zval (this function will decrement the reference counter, + // and only destruct if there are no other references left) + zval_ptr_dtor(&_val); + + // just copy the zval, and the refcounter + _val = value._val; + + // and we have one more reference + Z_ADDREF_P(_val); + } + + // update the object + return *this; } /** @@ -262,65 +262,65 @@ Value &Value::operator=(Value &&value) // skip self assignment if (this == &value) return *this; - // is the object a reference? - if (Z_ISREF_P(_val)) - { + // is the object a reference? + if (Z_ISREF_P(_val)) + { // @todo difference if the other object is a reference or not? - // the current object is a reference, this means that we should - // keep the zval object, and copy the other value into it, get - // the current refcount - int refcount = Z_REFCOUNT_P(_val); - - // clean up the current zval (but keep the zval structure) - zval_dtor(_val); - - // make the copy - *_val = *value._val; - - // restore reference and refcount setting - Z_SET_ISREF_TO_P(_val, true); - Z_SET_REFCOUNT_P(_val, refcount); + // the current object is a reference, this means that we should + // keep the zval object, and copy the other value into it, get + // the current refcount + int refcount = Z_REFCOUNT_P(_val); + + // clean up the current zval (but keep the zval structure) + zval_dtor(_val); + + // make the copy + *_val = *value._val; + + // restore reference and refcount setting + Z_SET_ISREF_TO_P(_val, true); + Z_SET_REFCOUNT_P(_val, refcount); // how many references did the old variable have? if (Z_ISREF_P(value._val) > 1) { - // the other object already had multiple references, this - // implies that many other PHP variables are also referring - // to it, and we still need to store its contents, with one - // reference less - Z_DELREF_P(value._val); - - // and we need to run the copy constructor on the current - // value, because we're making a deep copy - zval_copy_ctor(_val); - } - else - { - // the last and only reference to the other object was - // removed, we no longer need it - FREE_ZVAL(value._val); - - // the other object is no longer valid - value._val = nullptr; - } - } - else - { - // destruct the zval (this function will decrement the reference counter, - // and only destruct if there are no other references left) - zval_ptr_dtor(&_val); - - // just copy the zval completely - _val = value._val; - - // the other object is no longer valid - value._val = nullptr; - } - - // update the object - return *this; + // the other object already had multiple references, this + // implies that many other PHP variables are also referring + // to it, and we still need to store its contents, with one + // reference less + Z_DELREF_P(value._val); + + // and we need to run the copy constructor on the current + // value, because we're making a deep copy + zval_copy_ctor(_val); + } + else + { + // the last and only reference to the other object was + // removed, we no longer need it + FREE_ZVAL(value._val); + + // the other object is no longer valid + value._val = nullptr; + } + } + else + { + // destruct the zval (this function will decrement the reference counter, + // and only destruct if there are no other references left) + zval_ptr_dtor(&_val); + + // just copy the zval completely + _val = value._val; + + // the other object is no longer valid + value._val = nullptr; + } + + // update the object + return *this; } /** @@ -339,8 +339,8 @@ Value &Value::operator=(int value) // set new value ZVAL_LONG(_val, value); - // update the object - return *this; + // update the object + return *this; } /** @@ -359,8 +359,8 @@ Value &Value::operator=(long value) // set new value ZVAL_LONG(_val, value); - // update the object - return *this; + // update the object + return *this; } /** @@ -379,8 +379,8 @@ Value &Value::operator=(bool value) // set new value ZVAL_BOOL(_val, value); - // update the object - return *this; + // update the object + return *this; } /** @@ -399,8 +399,8 @@ Value &Value::operator=(char value) // set new value ZVAL_STRINGL(_val, &value, 1, 1); - // update the object - return *this; + // update the object + return *this; } /** @@ -419,8 +419,8 @@ Value &Value::operator=(const std::string &value) // set new value ZVAL_STRINGL(_val, value.c_str(), value.size(), 1); - // update the object - return *this; + // update the object + return *this; } /** @@ -439,8 +439,8 @@ Value &Value::operator=(const char *value) // set new value ZVAL_STRING(_val, value, 1); - // update the object - return *this; + // update the object + return *this; } /** @@ -459,8 +459,8 @@ Value &Value::operator=(double value) // set new value ZVAL_DOUBLE(_val, value); - // update the object - return *this; + // update the object + return *this; } /** |