diff options
Diffstat (limited to 'src/extension.cpp')
-rw-r--r-- | src/extension.cpp | 275 |
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(); } /** |