summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-09-11 08:00:28 -0700
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-09-11 08:00:28 -0700
commit68fd128d82819db1022137a45ca3224cee8ef029 (patch)
tree6f01d5456d830de9d24150ec56e5c1ee4d464faa
parentf08f5850fa39c42974e12e42fa101ffe51eef594 (diff)
The environment object that is passed to functions now always is the same environment object, added move operator= to Value class to make moving zvals faster, and added request startup and request closedown methods
-rw-r--r--include/extension.h40
-rw-r--r--include/globals.h58
-rw-r--r--include/value.h7
-rw-r--r--src/extension.cpp57
-rw-r--r--src/function.cpp5
-rw-r--r--src/includes.h2
-rw-r--r--src/value.cpp71
7 files changed, 193 insertions, 47 deletions
diff --git a/include/extension.h b/include/extension.h
index b322533..ceeed78 100644
--- a/include/extension.h
+++ b/include/extension.h
@@ -29,6 +29,11 @@ struct _zend_module_entry;
namespace Php {
/**
+ * Optional callback types for starting and stopping the request
+ */
+typedef bool (*request_callback)(Environment &);
+
+/**
* A couple of predefined native callback functions that can be registered.
* These are functions that optional accept a Request and/or Parameters object,
* and that either return void or a Value object.
@@ -52,9 +57,10 @@ public:
* Constructor that defines a number of functions right away
* @param name Extension name
* @param version Extension version string
- * @param functions The functions that are defined
+ * @param callback Function that is called when request starts
+ * @param callback Function that is called when request ends
*/
- Extension(const char *name = NULL, const char *version = NULL);
+ Extension(const char *name = NULL, const char *version = NULL, request_callback start = NULL, request_callback stop = NULL);
/**
* No copy'ing and no moving
@@ -109,6 +115,7 @@ public:
*/
virtual Environment *createEnvironment()
{
+ // allocate the environment
return new Environment(this);
}
@@ -121,6 +128,7 @@ public:
*/
virtual void deleteEnvironment(Environment *environment)
{
+ // destruct the environment
delete environment;
}
@@ -133,9 +141,13 @@ public:
*
* @return boolean
*/
- bool startRequest(Environment &environment)
+ virtual bool startRequest(Environment &environment)
{
- return true;
+ // ok if no callback was set
+ if (!_start) return true;
+
+ // call the callback function
+ return _start(environment);
}
/**
@@ -146,9 +158,13 @@ public:
*
* @return boolean
*/
- bool endRequest(Environment &environment)
+ virtual bool endRequest(Environment &environment)
{
- return true;
+ // ok if no callback is set
+ if (!_stop) return true;
+
+ // call callback
+ return _stop(environment);
}
/**
@@ -212,6 +228,18 @@ private:
*/
_zend_module_entry *_entry;
+ /**
+ * Callback that is called before each request
+ * @var request_callback
+ */
+ request_callback _start;
+
+ /**
+ * Callback that is called after each request
+ * @var request_callback
+ */
+ request_callback _stop;
+
};
/**
diff --git a/include/globals.h b/include/globals.h
new file mode 100644
index 0000000..052bab8
--- /dev/null
+++ b/include/globals.h
@@ -0,0 +1,58 @@
+/**
+ * Globals.h
+ *
+ * Variables and structured required by the Zend engine to work
+ * with global variables
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013 Copernica BV
+ */
+
+/**
+ * Namespace
+ */
+namespace Php {
+
+/**
+ * The way how PHP C API deals with "global" variables is stupid.
+ *
+ * This is supposed to turn into a structure that is going to be
+ * instantiated for each parallel running request, and for which the
+ * PHP engine allocates a certain amount of memory, and a magic
+ * pointer that is passed and should be forwarded to every thinkable
+ * PHP function.
+ *
+ * We don't like this architecture. We have our own environment object
+ * that makes much more sense, and that we use. However, we need
+ * to assign this object somewhere, so that's what we do in this
+ * one and only global variable
+ */
+ZEND_BEGIN_MODULE_GLOBALS(phpcpp)
+ Php::Environment *environment;
+ZEND_END_MODULE_GLOBALS(phpcpp)
+
+/**
+ * And now we're going to define a macro. This also is a ridiculous
+ * architecture from PHP to get access to a variable from the
+ * structure above.
+ */
+#ifdef ZTS
+#define PHPCPP_G(v) TSRMG(phpcpp_globals_id, phpcpp_globals *, v)
+#else
+#define PHPCPP_G(v) (phpcpp_globals.v)
+#endif
+
+/**
+ * We're almost there, we now need to declare an instance of the
+ * structure defined above (if building for a single thread) or some
+ * sort of impossible to understand magic pointer-to-a-pointer (for
+ * multi-threading builds). We make this a static variable because
+ * this already is bad enough.
+ */
+extern ZEND_DECLARE_MODULE_GLOBALS(phpcpp)
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/include/value.h b/include/value.h
index e4af1b7..4854437 100644
--- a/include/value.h
+++ b/include/value.h
@@ -124,6 +124,13 @@ public:
virtual Value &operator=(const Value &value);
/**
+ * Move assignment
+ * @param value
+ * @return Value
+ */
+ virtual Value &operator=(Value &&value);
+
+ /**
* Assignment operator
* @param value
* @return Value
diff --git a/src/extension.cpp b/src/extension.cpp
index 37082b2..b0d78f2 100644
--- a/src/extension.cpp
+++ b/src/extension.cpp
@@ -26,42 +26,13 @@ namespace Php {
static Extension *extension = nullptr;
/**
- * The way how PHP C API deals with "global" variables is stupid.
- *
- * This is supposed to turn into a structure that is going to be
- * instantiated for each parallel running request, and for which the
- * PHP engine allocates a certain amount of memory, and a magic
- * pointer that is passed and should be forwarded to every thinkable
- * PHP function.
- *
- * We don't like this architecture. We have our own request object
- * that makes much more sense, and that we use. However, we need
- * to assign this object somewhere, so that's what we do in this
- * one and only global variable
- */
-ZEND_BEGIN_MODULE_GLOBALS(phpcpp)
- Environment *environment;
-ZEND_END_MODULE_GLOBALS(phpcpp)
-
-/**
- * And now we're going to define a macro. This also is a ridiculous
- * architecture from PHP to get access to a variable from the
- * structure above.
- */
-#ifdef ZTS
-#define PHPCPP_G(v) TSRMG(phpcpp_globals_id, zend_phpcpp_globals *, v)
-#else
-#define PHPCPP_G(v) (phpcpp_globals.v)
-#endif
-
-/**
* We're almost there, we now need to declare an instance of the
* structure defined above (if building for a single thread) or some
* sort of impossible to understand magic pointer-to-a-pointer (for
* multi-threading builds). We make this a static variable because
* this already is bad enough.
*/
-static ZEND_DECLARE_MODULE_GLOBALS(phpcpp)
+ZEND_DECLARE_MODULE_GLOBALS(phpcpp)
/**
* Function that must be defined to initialize the "globals"
@@ -71,8 +42,6 @@ static ZEND_DECLARE_MODULE_GLOBALS(phpcpp)
*/
static void init_globals(zend_phpcpp_globals *globals) {}
-
-
/**
* Function that is called when the extension initializes
* @param type Module type
@@ -109,10 +78,16 @@ static int extension_shutdown(SHUTDOWN_FUNC_ARGS)
static int request_startup(INIT_FUNC_ARGS)
{
// create the environment
- PHPCPP_G(environment) = extension->createEnvironment();
+ Environment *environment = extension->createEnvironment();
+
+ // store in global structure
+ PHPCPP_G(environment) = environment;
+
+ // initialize the environment
+ environment->initialize();
// start the request
- return BOOL2SUCCESS(extension->startRequest(*(PHPCPP_G(environment))));
+ return BOOL2SUCCESS(environment->initialize() && extension->startRequest(*environment));
}
/**
@@ -123,11 +98,17 @@ static int request_startup(INIT_FUNC_ARGS)
*/
static int request_shutdown(INIT_FUNC_ARGS)
{
+ // retrieve the environment
+ Environment *environment = PHPCPP_G(environment);
+
// end the request
- bool success = extension->endRequest(*(PHPCPP_G(environment)));
+ bool success = extension->endRequest(*environment) && environment->finalize();
// deallocate the environment
- extension->deleteEnvironment(PHPCPP_G(environment));
+ extension->deleteEnvironment(environment);
+
+ // reset global variable
+ PHPCPP_G(environment) = NULL;
// done
return BOOL2SUCCESS(success);
@@ -137,8 +118,10 @@ static int request_shutdown(INIT_FUNC_ARGS)
* Constructor
* @param name Name of the extension
* @param version Version number
+ * @param start Request start callback
+ * @param stop Request stop callback
*/
-Extension::Extension(const char *name, const char *version)
+Extension::Extension(const char *name, const char *version, request_callback start, request_callback stop) : _start(start), _stop(stop)
{
// store extension variable
extension = this;
diff --git a/src/function.cpp b/src/function.cpp
index 10b47b9..2afc1be 100644
--- a/src/function.cpp
+++ b/src/function.cpp
@@ -37,11 +37,8 @@ void invoke_function(INTERNAL_FUNCTION_PARAMETERS)
// construct parameters
Parameters params(ZEND_NUM_ARGS());
- // @todo get the appropriate request (or environment)
- Environment environment(NULL);
-
// get the result
- result = function->invoke(environment, params);
+ result = function->invoke(*PHPCPP_G(environment), params);
}
/**
diff --git a/src/includes.h b/src/includes.h
index cfcff2a..1a60b67 100644
--- a/src/includes.h
+++ b/src/includes.h
@@ -45,8 +45,10 @@
#include "../include/parameters.h"
#include "../include/function.h"
#include "../include/extension.h"
+#include "../include/globals.h"
/**
* Interface files for internal use only
*/
#include "nativefunction.h"
+
diff --git a/src/value.cpp b/src/value.cpp
index 7f43724..4cdac58 100644
--- a/src/value.cpp
+++ b/src/value.cpp
@@ -244,6 +244,77 @@ Value &Value::operator=(const Value &value)
}
/**
+ * Move operator
+ * @param value
+ * @return Value
+ */
+Value &Value::operator=(Value &&value)
+{
+ // skip self assignment
+ if (this == &value) return *this;
+
+ // 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);
+
+ // 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;
+ }
+
+ // done
+ return *this;
+}
+
+/**
* Assignment operator
* @param value
* @return Value