summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-09-25 14:59:58 -0700
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-09-25 14:59:58 -0700
commitffdaa0590d33ea89d116f6c56df2474cc0675ec9 (patch)
tree6b0d71337879892b43a4af90e6757d53ecc77853 /src
parent753402a84b40ff4dc9697dea1d2d4aa037ea7624 (diff)
{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
Diffstat (limited to 'src')
-rw-r--r--src/classinfo.cpp153
-rw-r--r--src/extension.cpp8
-rw-r--r--src/function.cpp40
-rw-r--r--src/internalfunction.h11
-rw-r--r--src/nativefunction.h4
-rw-r--r--src/value.cpp206
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;
}
/**