summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-04-06 14:44:03 +0200
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-04-06 14:44:03 +0200
commit9bc5d1ed595e0ff0b7cec9a87d06a7923c211ebd (patch)
tree56681046544fce1bad3466a77b62194a4978ec89 /src
parent97269e8159b419fa624980ce70de908f22c4982c (diff)
removed all zend dependencies from the public extension object, and moved it into the src directory
Diffstat (limited to 'src')
-rw-r--r--src/callable.h12
-rw-r--r--src/extension.cpp275
-rw-r--r--src/extensionimpl.cpp300
-rw-r--r--src/extensionimpl.h213
-rw-r--r--src/function.h2
-rw-r--r--src/includes.h1
-rw-r--r--src/namespace.cpp79
7 files changed, 605 insertions, 277 deletions
diff --git a/src/callable.h b/src/callable.h
index aef5649..65ce719 100644
--- a/src/callable.h
+++ b/src/callable.h
@@ -9,12 +9,6 @@
*/
/**
- * Forward definitions
- */
-struct _zend_function_entry;
-struct _zend_arg_info;
-
-/**
* Set up namespace
*/
namespace Php {
@@ -99,7 +93,7 @@ public:
* @param classname Optional class name
* @param flags Access flags
*/
- void initialize(struct _zend_function_entry *entry, const char *classname = nullptr, int flags = 0) const;
+ void initialize(zend_function_entry *entry, const char *classname = nullptr, int flags = 0) const;
/**
* Fill function info
@@ -107,7 +101,7 @@ public:
* @param ns Active namespace
* @param classname Optional class name
*/
- void initialize(struct _zend_arg_info *info, const char *classname = nullptr) const;
+ void initialize(zend_arg_info *info, const char *classname = nullptr) const;
protected:
@@ -139,7 +133,7 @@ protected:
* The arguments
* @var zend_arg_info[]
*/
- struct _zend_arg_info *_argv = nullptr;
+ zend_arg_info *_argv = nullptr;
/**
* Private helper method to fill an argument object
diff --git a/src/extension.cpp b/src/extension.cpp
index 949efa9..9685b32 100644
--- a/src/extension.cpp
+++ b/src/extension.cpp
@@ -2,7 +2,7 @@
* Extension.cpp
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
+ * @copyright 2013, 2014 Copernica BV
*/
#include "includes.h"
@@ -12,265 +12,88 @@
namespace Php {
/**
- * If this extension is compiled for a PHP version with multi
- * threading support, we need an additional header file
+ * Constructor that defines a number of functions right away
+ * @param name Extension name
+ * @param version Extension version string
*/
-#ifdef ZTS
-#include "TSRM.h"
-#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.
- */
-ZEND_DECLARE_MODULE_GLOBALS(phpcpp)
-
-/**
- * Function that must be defined to initialize the "globals"
- * We do not have to initialize anything, but PHP needs to call this
- * method (crazy)
- * @param globals
- */
-static void init_globals(zend_phpcpp_globals *globals) {}
-
-/**
- * The *startup() and *shutdown() callback functions are passed a module_number
- * variable. However, there does not seem to be a decent API call in Zend to
- * get back the original module_entry linked to this number. So we have to
- * look up entries in a hash table to find the right module entry. To make things
- * even worse, the records in this hash table are copies of the original
- * zend_module_entry structure, so we can also not hide the C++ extension
- * object pointer in the entry that we created ourselves.
- *
- * We have an ugly solution, we keep track of a map of all C++ extension names
- * and their associated extension object, and a map of all module number and
- * the linked extension object.
- *
- * @var map
- */
-static std::map<std::string,Extension*> name2extension;
-static std::map<int,Extension*> number2extension;
-
-/**
- * Handler function that is used in combination with zend_hash_apply()
- *
- * This function is called when we need to find an extension object based on
- * an extension number. We loop through the list of all registered modules, and
- * for each module we check if we know the extension based on the name
- *
- * @param _zend_module_entry
- */
-static int match_module(_zend_module_entry *entry)
-{
- // check if there is an extension with this name
- auto iter = name2extension.find(entry->name);
- if (iter == name2extension.end()) return ZEND_HASH_APPLY_KEEP;
-
- // we have the extension, store in combination with the number
- number2extension[entry->module_number] = iter->second;
-
- // done
- return ZEND_HASH_APPLY_KEEP;
-}
-
-/**
- * Find an extension based on the module number
- * @param number
- * @param tsrm_ls
- * @return Extension*
- */
-static Extension *find(int number TSRMLS_DC)
-{
- // do we already have an extension with this number?
- auto iter = number2extension.find(number);
- if (iter != number2extension.end()) return iter->second;
-
- // no, not yet, loop through all modules
- zend_hash_apply(&module_registry, (apply_func_t)match_module TSRMLS_CC);
-
- // find again
- iter = number2extension.find(number);
- if (iter == number2extension.end()) return nullptr;
-
- // found!
- return iter->second;
-}
-
-/**
- * Function that is called when the extension initializes
- * @param type Module type
- * @param number Module number
- * @param tsrm_ls
- * @return int 0 on success
- */
-int Extension::onStartup(int type, int module_number TSRMLS_DC)
-{
- // initialize and allocate the "global" variables
- ZEND_INIT_MODULE_GLOBALS(phpcpp, init_globals, NULL);
+Extension::Extension(const char *name, const char *version) :
+ Namespace(""), _impl(new ExtensionImpl(this, name, version)) {}
- // get the extension
- Extension *extension = find(module_number TSRMLS_CC);
-
- // initialize namespace
- extension->initialize("" TSRMLS_CC);
-
- // is the callback registered?
- if (extension->_onStartup) extension->_onStartup();
-
- // done
- return BOOL2SUCCESS(true);
-}
-
/**
- * Function that is called when the extension is about to be stopped
- * @param type Module type
- * @param number Module number
- * @param tsrm_ls
- * @return int
+ * Destructor
*/
-int Extension::onShutdown(int type, int module_number TSRMLS_DC)
+Extension::~Extension()
{
- // get the extension
- Extension *extension = find(module_number TSRMLS_CC);
-
- // is the callback registered?
- if (extension->_onShutdown) extension->_onShutdown();
-
- // done
- return BOOL2SUCCESS(true);
+ // get rid of the implementation object
+ delete _impl;
}
/**
- * Function that is called when a request starts
- * @param type Module type
- * @param number Module number
- * @param tsrm_ls
- * @return int 0 on success
+ * Register a function to be called when the PHP engine is ready
+ * @param callback
+ * @return Extension
*/
-int Extension::onRequest(int type, int module_number TSRMLS_DC)
+Extension &Extension::onStartup(const Callback &callback)
{
- // get the extension
- Extension *extension = find(module_number TSRMLS_CC);
-
- // is the callback registered?
- if (extension->_onRequest) extension->_onRequest();
+ // pass on to the implementation
+ _impl->onStartup(callback);
- // done
- return BOOL2SUCCESS(true);
+ // allow chaining
+ return *this;
}
/**
- * Function that is called when a request is ended
- * @param type Module type
- * @param number Module number
- * @param tsrm_ls
- * @return int 0 on success
+ * Register a function to be called when the PHP engine is going to stop
+ * @param callback
+ * @return Extension
*/
-int Extension::onIdle(int type, int module_number TSRMLS_DC)
+Extension &Extension::onShutdown(const Callback &callback)
{
- // get the extension
- Extension *extension = find(module_number TSRMLS_CC);
+ // pass on to the implementation
+ _impl->onShutdown(callback);
- // is the callback registered?
- if (extension->_onIdle) extension->_onIdle();
-
- // done
- return BOOL2SUCCESS(true);
+ // allow chaining
+ return *this;
}
/**
- * Constructor
- * @param name Name of the extension
- * @param version Version number
- * @param start Request start callback
- * @param stop Request stop callback
+ * Register a callback that is called at the beginning of each pageview/request
+ * @param callback
*/
-Extension::Extension(const char *name, const char *version) : Namespace("")
+Extension &Extension::onRequest(const Callback &callback)
{
- // keep extension pointer based on the name
- name2extension[name] = 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
- // PHP-C++ library is to have an interface that is as simple as possible
- _entry = new _zend_module_entry;
+ // pass on to the implementation
+ _impl->onRequest(callback);
- // assign all members (apart from the globals)
- _entry->size = sizeof(zend_module_entry); // size of the data
- _entry->zend_api = ZEND_MODULE_API_NO; // api number
- _entry->zend_debug = ZEND_DEBUG; // debug mode enabled?
- _entry->zts = USING_ZTS; // is thread safety enabled?
- _entry->ini_entry = NULL; // the php.ini record
- _entry->deps = NULL; // dependencies on other modules
- _entry->name = name; // extension name
- _entry->functions = NULL; // functions supported by this module (none for now)
- _entry->module_startup_func = &Extension::onStartup; // startup function for the whole extension
- _entry->module_shutdown_func = &Extension::onShutdown; // shutdown function for the whole extension
- _entry->request_startup_func = &Extension::onRequest; // startup function per request
- _entry->request_shutdown_func = &Extension::onIdle; // shutdown function per request
- _entry->info_func = NULL; // information for retrieving info
- _entry->version = version; // version string
- _entry->globals_size = 0; // size of the global variables
- _entry->globals_ctor = NULL; // constructor for global variables
- _entry->globals_dtor = NULL; // destructor for global variables
- _entry->post_deactivate_func = NULL; // unknown function
- _entry->module_started = 0; // module is not yet started
- _entry->type = 0; // temporary or persistent module, will be filled by Zend engine
- _entry->handle = NULL; // dlopen() handle, will be filled by Zend engine
- _entry->module_number = 0; // module number will be filled in by Zend engine
- _entry->build_id = (char *)ZEND_MODULE_BUILD_ID; // check if extension and zend engine are compatible
-
- // things that only need to be initialized
-#ifdef ZTS
- _entry->globals_id_ptr = NULL;
-#else
- _entry->globals_ptr = NULL;
-#endif
-
+ // allow chaining
+ return *this;
}
/**
- * Destructor
+ * Register a callback that is called to cleanup things after a pageview/request
+ * @param callback
*/
-Extension::~Extension()
+Extension &Extension::onIdle(const Callback &callback)
{
- // deallocate functions
- if (_entry->functions) delete[] _entry->functions;
+ // pass on to the implementation
+ _impl->onIdle(callback);
- // deallocate entry
- delete _entry;
+ // allow chaining
+ return *this;
}
/**
- * Retrieve the module entry
- * @return zend_module_entry
+ * Retrieve the module pointer
+ *
+ * This is the memory address that should be exported by the get_module()
+ * function.
+ *
+ * @return void*
*/
-zend_module_entry *Extension::module()
+void *Extension::module()
{
- // check if functions we're already defined
- if (_entry->functions || _functions.size() == 0) return _entry;
-
- // allocate memory for the functions
- zend_function_entry *entries = new zend_function_entry[functions() + 1];
-
- // initialize the entries
- int count = Namespace::initialize("", entries);
-
- // last entry should be set to all zeros
- zend_function_entry *last = &entries[count];
-
- // all should be set to zero
- memset(last, 0, sizeof(zend_function_entry));
-
- // store functions in entry object
- _entry->functions = entries;
-
- // return the entry
- return _entry;
+ // pass on to the implementation
+ return _impl->module();
}
/**
diff --git a/src/extensionimpl.cpp b/src/extensionimpl.cpp
new file mode 100644
index 0000000..0197757
--- /dev/null
+++ b/src/extensionimpl.cpp
@@ -0,0 +1,300 @@
+/**
+ * Extension.cpp
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013 Copernica BV
+ */
+#include "includes.h"
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * If this extension is compiled for a PHP version with multi
+ * threading support, we need an additional header file
+ */
+#ifdef ZTS
+#include "TSRM.h"
+#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.
+ */
+ZEND_DECLARE_MODULE_GLOBALS(phpcpp)
+
+/**
+ * Function that must be defined to initialize the "globals"
+ * We do not have to initialize anything, but PHP needs to call this
+ * method (crazy)
+ * @param globals
+ */
+static void init_globals(zend_phpcpp_globals *globals) {}
+
+/**
+ * The *startup() and *shutdown() callback functions are passed a module_number
+ * variable. However, there does not seem to be a decent API call in Zend to
+ * get back the original module_entry linked to this number. So we have to
+ * look up entries in a hash table to find the right module entry. To make things
+ * even worse, the records in this hash table are copies of the original
+ * zend_module_entry structure, so we can also not hide the C++ extension
+ * object pointer in the entry that we created ourselves.
+ *
+ * We have an ugly solution, we keep track of a map of all C++ extension names
+ * and their associated extension object, and a map of all module number and
+ * the linked extension object.
+ *
+ * @var map
+ */
+static std::map<std::string,ExtensionImpl*> name2extension;
+static std::map<int,ExtensionImpl*> number2extension;
+
+/**
+ * Handler function that is used in combination with zend_hash_apply()
+ *
+ * This function is called when we need to find an extension object based on
+ * an extension number. We loop through the list of all registered modules, and
+ * for each module we check if we know the extension based on the name
+ *
+ * @param zend_module_entry
+ */
+static int match_module(zend_module_entry *entry)
+{
+ // check if there is an extension with this name
+ auto iter = name2extension.find(entry->name);
+ if (iter == name2extension.end()) return ZEND_HASH_APPLY_KEEP;
+
+ // we have the extension, store in combination with the number
+ number2extension[entry->module_number] = iter->second;
+
+ // done
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+/**
+ * Find an extension based on the module number
+ * @param number
+ * @param tsrm_ls
+ * @return Extension*
+ */
+static ExtensionImpl *find(int number TSRMLS_DC)
+{
+ // do we already have an extension with this number?
+ auto iter = number2extension.find(number);
+ if (iter != number2extension.end()) return iter->second;
+
+ // no, not yet, loop through all modules
+ zend_hash_apply(&module_registry, (apply_func_t)match_module TSRMLS_CC);
+
+ // find again
+ iter = number2extension.find(number);
+ if (iter == number2extension.end()) return nullptr;
+
+ // found!
+ return iter->second;
+}
+
+/**
+ * Function that is called when the extension initializes
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+int ExtensionImpl::onStartup(int type, int module_number TSRMLS_DC)
+{
+ // initialize and allocate the "global" variables
+ ZEND_INIT_MODULE_GLOBALS(phpcpp, init_globals, NULL);
+
+ // get the extension
+ auto *extension = find(module_number TSRMLS_CC);
+
+ // initialize the extension
+ extension->initialize(TSRMLS_CC);
+
+ // is the callback registered?
+ if (extension->_onStartup) extension->_onStartup();
+
+ // done
+ return BOOL2SUCCESS(true);
+}
+
+/**
+ * Function that is called when the extension is about to be stopped
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int
+ */
+int ExtensionImpl::onShutdown(int type, int module_number TSRMLS_DC)
+{
+ // get the extension
+ auto *extension = find(module_number TSRMLS_CC);
+
+ // is the callback registered?
+ if (extension->_onShutdown) extension->_onShutdown();
+
+ // done
+ return BOOL2SUCCESS(true);
+}
+
+/**
+ * Function that is called when a request starts
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+int ExtensionImpl::onRequest(int type, int module_number TSRMLS_DC)
+{
+ // get the extension
+ auto *extension = find(module_number TSRMLS_CC);
+
+ // is the callback registered?
+ if (extension->_onRequest) extension->_onRequest();
+
+ // done
+ return BOOL2SUCCESS(true);
+}
+
+/**
+ * Function that is called when a request is ended
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+int ExtensionImpl::onIdle(int type, int module_number TSRMLS_DC)
+{
+ // get the extension
+ auto *extension = find(module_number TSRMLS_CC);
+
+ // is the callback registered?
+ if (extension->_onIdle) extension->_onIdle();
+
+ // done
+ return BOOL2SUCCESS(true);
+}
+
+/**
+ * Constructor
+ * @param data Pointer to the extension object created by the extension programmer
+ * @param name Name of the extension
+ * @param version Version number
+ */
+ExtensionImpl::ExtensionImpl(Extension *data, const char *name, const char *version) : _data(data)
+{
+ // keep extension pointer based on the name
+ name2extension[name] = this;
+
+ // assign all members (apart from the globals)
+ _entry.size = sizeof(zend_module_entry); // size of the data
+ _entry.zend_api = ZEND_MODULE_API_NO; // api number
+ _entry.zend_debug = ZEND_DEBUG; // debug mode enabled?
+ _entry.zts = USING_ZTS; // is thread safety enabled?
+ _entry.ini_entry = NULL; // the php.ini record
+ _entry.deps = NULL; // dependencies on other modules
+ _entry.name = name; // extension name
+ _entry.functions = NULL; // functions supported by this module (none for now)
+ _entry.module_startup_func = &ExtensionImpl::onStartup; // startup function for the whole extension
+ _entry.module_shutdown_func = &ExtensionImpl::onShutdown; // shutdown function for the whole extension
+ _entry.request_startup_func = &ExtensionImpl::onRequest; // startup function per request
+ _entry.request_shutdown_func = &ExtensionImpl::onIdle; // shutdown function per request
+ _entry.info_func = NULL; // information for retrieving info
+ _entry.version = version; // version string
+ _entry.globals_size = 0; // size of the global variables
+ _entry.globals_ctor = NULL; // constructor for global variables
+ _entry.globals_dtor = NULL; // destructor for global variables
+ _entry.post_deactivate_func = NULL; // unknown function
+ _entry.module_started = 0; // module is not yet started
+ _entry.type = 0; // temporary or persistent module, will be filled by Zend engine
+ _entry.handle = NULL; // dlopen() handle, will be filled by Zend engine
+ _entry.module_number = 0; // module number will be filled in by Zend engine
+ _entry.build_id = (char *)ZEND_MODULE_BUILD_ID; // check if extension and zend engine are compatible
+
+ // things that only need to be initialized
+#ifdef ZTS
+ _entry.globals_id_ptr = NULL;
+#else
+ _entry.globals_ptr = NULL;
+#endif
+
+}
+
+/**
+ * Destructor
+ */
+ExtensionImpl::~ExtensionImpl()
+{
+ // deallocate functions
+ if (_entry.functions) delete[] _entry.functions;
+}
+
+/**
+ * Retrieve the module entry
+ * @return zend_module_entry
+ */
+zend_module_entry *ExtensionImpl::module()
+{
+ // check if functions we're already defined
+ if (_entry.functions) return &_entry;
+
+ // the number of functions
+ int count = _data->functions();
+
+ // skip if there are no functions
+ if (count == 0) return &_entry;
+
+ // allocate memory for the functions
+ zend_function_entry *entries = new zend_function_entry[count + 1];
+
+ // index being processed
+ int i = 0;
+
+ // apply a function to each function
+ _data->apply([&i, entries](const std::string &prefix, Function &function) {
+
+ // initialize the function
+ function.initialize(prefix, &entries[i]);
+
+ // move on to the next iteration
+ i++;
+ });
+
+ // last entry should be set to all zeros
+ zend_function_entry *last = &entries[count];
+
+ // all should be set to zero
+ memset(last, 0, sizeof(zend_function_entry));
+
+ // store functions in entry object
+ _entry.functions = entries;
+
+ // return the entry
+ return &_entry;
+}
+
+/**
+ * Initialize the extension after it was started
+ * @param tsrm_ls
+ */
+void ExtensionImpl::initialize(TSRMLS_D)
+{
+ // we need to register each class, find out all classes
+ _data->apply([TSRMLS_C](const std::string &prefix, ClassBase &c) {
+
+ // forward to implementation class
+ c.implementation()->initialize(&c, prefix TSRMLS_C);
+ });
+}
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/src/extensionimpl.h b/src/extensionimpl.h
new file mode 100644
index 0000000..8c9ae58
--- /dev/null
+++ b/src/extensionimpl.h
@@ -0,0 +1,213 @@
+/**
+ * ExtensionImpl.h
+ *
+ * Extension implementation for the Zend engine.
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013, 2014 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class ExtensionImpl
+{
+protected:
+ /**
+ * Pointer to the extension object that is filled by the extension programmer
+ * @var Extension
+ */
+ Extension *_data;
+
+ /**
+ * The information that is passed to the Zend engine
+ *
+ * Although it would be slightly faster to not make this a pointer, this
+ * would require that client code also includes the PHP header files, which
+ * we try to prevent with the PHP-CPP library, so we allocate it dynamically.
+ *
+ * @var zend_module_entry
+ */
+ zend_module_entry _entry;
+
+ /**
+ * Callback that is called after the engine is initialized and before the
+ * pageviews are going to be handled
+ * @var Callback
+ */
+ Callback _onStartup;
+
+ /**
+ * Callback that is called in front of each request
+ * @var Callback
+ */
+ Callback _onRequest;
+
+ /**
+ * Callback that is called right after each request
+ * @var Callback
+ */
+ Callback _onIdle;
+
+ /**
+ * Callback that is called right before the engine is closing down
+ * @var Callback
+ */
+ Callback _onShutdown;
+
+public:
+ /**
+ * Constructor
+ * @param data Extension object created by the extension programmer
+ * @param name Name of the extension
+ * @param version Version number
+ */
+ ExtensionImpl(Extension *data, const char *name, const char *version);
+
+ /**
+ * No copy'ing and no moving
+ */
+ ExtensionImpl(const ExtensionImpl &extension) = delete;
+ ExtensionImpl(ExtensionImpl &&extension) = delete;
+
+ /**
+ * Destructor
+ */
+ virtual ~ExtensionImpl();
+
+ /**
+ * Register a function to be called when the PHP engine is ready
+ *
+ * The callback will be called after all extensions are loaded, and all
+ * functions and classes are available, but before the first pageview/request
+ * is handled. You can register this callback if you want to be notified
+ * when the engine is ready, for example to initialize certain things.
+ *
+ * @param callback
+ */
+ void onStartup(const Callback &callback)
+ {
+ // copy callback
+ _onStartup = callback;
+ }
+
+ /**
+ * Register a function to be called when the PHP engine is going to stop
+ *
+ * The callback will be called right before the process is going to stop.
+ * You can register a function if you want to clean up certain things.
+ *
+ * @param callback
+ */
+ void onShutdown(const Callback &callback)
+ {
+ // copy callback
+ _onShutdown = callback;
+ }
+
+ /**
+ * Register a callback that is called at the beginning of each pageview/request
+ *
+ * You can register a callback if you want to initialize certain things
+ * at the beginning of each request. Remember that the extension can handle
+ * multiple requests after each other, and you may want to set back certain
+ * global variables to their initial variables in front of each request
+ *
+ * @param callback
+ */
+ void onRequest(const Callback &callback)
+ {
+ // copy callback
+ _onRequest = callback;
+ }
+
+ /**
+ * Register a callback that is called to cleanup things after a pageview/request
+ *
+ * The callback will be called after _each_ request, so that you can clean up
+ * certain things and make your extension ready to handle the next request.
+ * This method is called onIdle because the extension is idle in between
+ * requests.
+ *
+ * @param callback
+ */
+ void onIdle(const Callback &callback)
+ {
+ // copy callback
+ _onIdle = callback;
+ }
+
+ /**
+ * Retrieve the module entry
+ *
+ * This is the memory address that should be exported by the get_module()
+ * function.
+ *
+ * @return _zend_module_entry
+ */
+ zend_module_entry *module();
+
+ /**
+ * Cast to a module entry
+ * @return _zend_module_entry*
+ */
+ operator zend_module_entry * ()
+ {
+ return module();
+ }
+
+private:
+ /**
+ * Initialize the namespace after it was registered
+ * @param tsrm_ls
+ */
+ void initialize(TSRMLS_DC);
+
+ /**
+ * Function that is called when the extension initializes
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+ static int onStartup(int type, int module_number TSRMLS_DC);
+
+ /**
+ * Function that is called when the extension is about to be stopped
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int
+ */
+ static int onShutdown(int type, int module_number TSRMLS_DC);
+
+ /**
+ * Function that is called when a request starts
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+ static int onRequest(int type, int module_number TSRMLS_DC);
+
+ /**
+ * Function that is called when a request is ended
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+ static int onIdle(int type, int module_number TSRMLS_DC);
+};
+
+/**
+ * End of namespace
+ */
+}
+
+
diff --git a/src/function.h b/src/function.h
index fd60944..4c34ac7 100644
--- a/src/function.h
+++ b/src/function.h
@@ -67,7 +67,7 @@ public:
* @param prefix Active namespace prefix
* @param entry Entry to be filled
*/
- void initialize(const std::string &prefix, struct _zend_function_entry *entry)
+ void initialize(const std::string &prefix, zend_function_entry *entry)
{
// if there is a namespace prefix, we should adjust the name
if (prefix.size()) _ptr = HiddenPointer<Callable>(this, prefix+"\\"+(const char *)_ptr);
diff --git a/src/includes.h b/src/includes.h
index f725ae1..48df910 100644
--- a/src/includes.h
+++ b/src/includes.h
@@ -100,6 +100,7 @@
#include "iteratorimpl.h"
#include "streambuf.h"
#include "classimpl.h"
+#include "extensionimpl.h"
#ifndef ZVAL_COPY_VALUE
#define ZVAL_COPY_VALUE(z, v) \
diff --git a/src/namespace.cpp b/src/namespace.cpp
index d462684..bea31a1 100644
--- a/src/namespace.cpp
+++ b/src/namespace.cpp
@@ -78,58 +78,55 @@ Namespace &Namespace::add(const char *name, const native_callback_3 &function, c
}
/**
- * Initialize all functions in this namespace
- * @param parent Namespace prefix of the parent
- * @param entries The array to be filled
- * @return int Number of functions that were initialized
+ * Apply a callback to each registered function
+ *
+ * The callback will be called with the name of the namespace, and
+ * a reference to the registered function.
+ *
+ * @param callback
*/
-size_t Namespace::initialize(const std::string &parent, struct _zend_function_entry entries[])
+void Namespace::apply(const std::function<void(const std::string &ns, Function &func)> &callback)
{
- // keep iterator counter
- int count = 0;
-
- // the namespace to use
- std::string prefix = parent.size() ? parent + "\\" + _name : _name;
-
- // loop through the functions
- for (auto &function : _functions)
- {
- // retrieve entry
- zend_function_entry *entry = &entries[count++];
-
- // let the function fill the entry
- function->initialize(prefix, entry);
- }
+ // loop through the functions, and apply the callback
+ for (auto &function : _functions) callback(_name, *function);
- // loop through the namespace
- for (auto &ns : _namespaces)
- {
- // let the namespace initialize
- count += ns->initialize(prefix, &entries[count]);
- }
-
- // done
- return count;
+ // loop through the other namespaces
+ for (auto &ns : _namespaces) ns->apply([this, callback](const std::string &ns, Function &func) {
+
+ // if this is the root namespace, we don't have to change the prefix
+ if (_name.size() == 0) return callback(ns, func);
+
+ // construct a new prefix
+ // @todo this could be slightly inefficient
+ return callback(_name + "\\" + ns, func);
+ });
}
/**
- * Initialize the namespace after it was registered
- * @param parent Parent namespace
- * @param tsrm_ls
+ * Apply a callback to each registered class
+ *
+ * The callback will be called with the name of the namespace, and
+ * a reference to the registered class.
+ *
+ * @param callback
*/
-void Namespace::initialize(const std::string &parent TSRMLS_DC)
+void Namespace::apply(const std::function<void(const std::string &ns, ClassBase &clss)> &callback)
{
- // the namespace to use
- std::string prefix = parent.size() ? parent + "\\" + _name : _name;
+ // loop through the classes, and apply the callback
+ for (auto &c : _classes) callback(_name, *c);
- // loop through the classes in this namespace
- for (auto &c : _classes) c->implementation()->initialize(c.get(), prefix TSRMLS_CC);
-
- // and loop through the other namespaces
- for (auto &n : _namespaces) n->initialize(prefix TSRMLS_CC);
+ // loop through the other namespaces
+ for (auto &ns : _namespaces) ns->apply([this, callback](const std::string &ns, ClassBase &clss) {
+
+ // if this is the root namespace, we don't have to change the prefix
+ if (_name.size() == 0) return callback(ns, clss);
+
+ // construct a new prefix
+ // @todo this could be slightly inefficient
+ return callback(_name + "\\" + ns, clss);
+ });
}
-
/**
* End namespace
*/