summaryrefslogtreecommitdiff
path: root/src/extension.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/extension.cpp')
-rw-r--r--src/extension.cpp275
1 files changed, 49 insertions, 226 deletions
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();
}
/**