diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-08 19:36:16 +0100 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-08 19:36:16 +0100 |
commit | 25e162cbf64763245def4d11b4be40ced11ee330 (patch) | |
tree | 0d134472991c19278525bfc0c2e4cbeebca8dca2 | |
parent | 8b64e27a4ac8000c08d154b6343cf6bcd537a014 (diff) |
added information about Php::GLOBALS to the documentation, added article about the lifetime of an extension
-rw-r--r-- | documentation/calling-functions-and-methods.html | 2 | ||||
-rw-r--r-- | documentation/extension-lifetime.html | 113 | ||||
-rw-r--r-- | documentation/variables.html | 46 | ||||
-rw-r--r-- | include/extension.h | 115 |
4 files changed, 223 insertions, 53 deletions
diff --git a/documentation/calling-functions-and-methods.html b/documentation/calling-functions-and-methods.html index 5a0da07..8e2e7ba 100644 --- a/documentation/calling-functions-and-methods.html +++ b/documentation/calling-functions-and-methods.html @@ -159,5 +159,5 @@ lambda function called with param some parameter <p> If you call a function or a method that does not exist, a Php::Exception will be thrown. If you do not catch this exception in your C++ code, it - will bubble up and also appear in PHP user space as an exception. + will bubble up and appear in PHP user space. </p> diff --git a/documentation/extension-lifetime.html b/documentation/extension-lifetime.html new file mode 100644 index 0000000..10ce12a --- /dev/null +++ b/documentation/extension-lifetime.html @@ -0,0 +1,113 @@ +<h1>The lifetime of an extension</h1> +<p> + As we <a href="loading-extension">explained before</a>, the get_module() + function is called when your extension is started. It returns a memory address + where the Zend engine can find all relevant information about your extension, so + that your functions and classes can be seen from PHP scripts. +</p> +<p> + After this get_module() call, your extension is loaded and will be used to handle + <i>multiple pageviews</i>. This is an important difference between standard + PHP scripts and native extensions, because standard PHP scripts handle only a single + pageview. Extension can be used to serve multiple pageviews after + each other. +</p> +<p> + This difference is especially important when you use global variables. Global + variables are initialized when the extension is loaded - and not at the beginning + of each pageview. Changes that you make to global variables keep their value, + and subsequent requests will see the updated value. If you do not want this, + you can register callback functions that get called in front of each + request and right after each request. In these callback you can then + re-initialize the global variables. +</p> +<p> +<pre class="language-c++"><code>#include <phpcpp.h> +#include <iostream> + +/** + * Global value that keeps track of the number + * of requests that have been handled + * @var int + */ +int requestCount = 0; + +/** + * Global value that stores the number of times + * the function updateCounters() has been called in total + * @var int + */ +int invokeTotalCount = 0; + +/** + * Global value that keeps track how many times the + * function updateCounters() was called during the + * current request + * @var int + */ +int invokeDuringRequestCount = 0; + +/** + * Native function that is callable from PHP + * + * This function updates a number of global variables that count + * the number of times a function was called + */ +void updateCounters() +{ + // increment global counters + invokeTotalCount++; + invokeDuringRequestCount++; +} + +/** + * Switch to C context, because the Zend engine expects get get_module() + * to have a C style function signature + */ +extern "C" { + /** + * Startup function that is automatically called by the Zend engine + * when PHP starts, and that should return the extension details + * @return void* + */ + PHPCPP_EXPORT void *get_module() + { + // the extension object + static Php::Extension extension("my_extension", "1.0"); + + // install a callback function that is called when the PHP engine + // is fully initialized + extension.onReady([]() { + + // set global variables to their initial values + requestCount = 0; + invokeTotalCount = 0; + }); + + // install a callback that is called at the beginning of each + // request + extension.onRequest([]() { + + // re-initialize the counter + invokeDuringRequestCount = 0; + }); + + // install a callback that is called after each request + extension.onCleanup([]() { + + // @todo add your own implementation + + }); + + // install a callback that is called when the Zend engine + // is closing down + extension.onFinalize([]() { + + // @todo add your own implementation + }); + + // return the extension details + return extension; + } +}</code></pre> +</p> diff --git a/documentation/variables.html b/documentation/variables.html index 2985ce5..4d8ba34 100644 --- a/documentation/variables.html +++ b/documentation/variables.html @@ -156,13 +156,20 @@ array[0] = "apple"; array[1] = "banana"; array[2] = "tomato"; +// an initializer list can be used to create a filled array +Php::Value filled({ "a", "b", "c", "d"}); + +// you can cast an array to a vector, template parameter can be +// any type that a Value object is compatible with (string, int, etc) +std::vector<std::string> fruit = array; + // create an associative array Php::Value assoc; assoc["apple"] = "green"; assoc["banana"] = "yellow"; assoc["tomato"] = "green"; -// array values do not all have to be of the same type +// the variables in an array do not all have to be of the same type Php::Value assoc2; assoc2["x"] = "info@example.com"; assoc2["y"] = nullptr; @@ -175,6 +182,10 @@ assoc2["y"] = nullptr; assoc2["z"][0] = "a"; assoc2["z"][1] = "b"; assoc2["z"][2] = "c"; + +// assoc arrays can be cast to a map, indexed by string +std::map<std::string,std::string> map = assoc2; + </code></pre> </p> <p> @@ -272,3 +283,36 @@ array[1] = "format"; std::cout << array("Y-m-d H:i:s") << std::endl; </code></pre> </p> +<h2>Global variables</h2> +<p> + To read or update global PHP variables, you can use the Php::GLOBALS + variable. This variable works more or less the same as the $_GLOBALS + variable in a PHP script. +</p> +<p> +<pre class="language-c++"><code> +// set a global PHP variable +Php::GLOBALS["a"] = 12345; + +// global variables can be of any type +Php::GLOBALS["b"] = Php::Array({1,2,3,4}); + +// nested calls are (of course) supported +Php::GLOBALS["b"][4] = 5; + +// and global variables can also be read +std::cout << Php::GLOBALS["b"] << std::endl; +</code></pre> +</p> +<p> + Unlike PHP scripts, that handles only single pageviews, an extension is + used to handle multiple pageviews after each other. This means that when + you use global C++ (!) variables in your extension, that these variables are + not set back to their initial value in between the pageviews. The + Php::GLOBALS variable however, is always re-initialized at the beginning + of every new pageview. +</p> +<p> + You can read more about this in the article about the + <a href="extension-lifetime">the extension lifetime</a>. +</p> diff --git a/include/extension.h b/include/extension.h index f04dc8c..42bbff2 100644 --- a/include/extension.h +++ b/include/extension.h @@ -11,11 +11,8 @@ * as module in a webserver) many requests are handled by the same extension * instance. * - * This is a template class. You need to pass in the type of an object - * that you use for storing request specific state information. - * * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> - * @copyright 2013 Copernica BV + * @copyright 2013, 2014 Copernica BV */ /** @@ -34,10 +31,9 @@ namespace Php { class Extension; /** - * Optional callback types for starting and stopping the request - * @param extension + * Signature of a callback */ -typedef bool (*request_callback)(Extension *extension); +using Callback = std::function<void()>; /** * Class definition @@ -49,10 +45,8 @@ public: * Constructor that defines a number of functions right away * @param name Extension name * @param version Extension version string - * @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, request_callback start = NULL, request_callback stop = NULL); + Extension(const char *name = NULL, const char *version = NULL); /** * No copy'ing and no moving @@ -66,69 +60,63 @@ public: virtual ~Extension(); /** - * Initialize the extension after it was registered + * Register a function to be called when the PHP engine is ready * - * You can override this method to add your own initialization code. The - * default implementation registers all classes and namespaces + * 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. * - * @return bool + * @param callback */ - virtual bool initialize() + void onReady(const Callback &callback) { - // initialize the namespace - Namespace::initialize(""); - - // ok - return true; + // copy callback + _onReady = callback; } /** - * Finalize the extension after it was registered - * - * You can override this method to do your own cleanup right before the - * extension object is going to be destructed + * 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. * - * @return bool + * @param callback */ - virtual bool finalize() + void onFinalize(const Callback &callback) { - // ok - return true; + // copy callback + _onFinalize = callback; } - + /** - * Start a request + * Register a callback that is called at the beginning of each pageview/request * - * This method is called when the zend engine is about to start a new - * request. Internally, it calls the request() method to instantiate - * a new request object, and after that it initializes the 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 * - * @return boolean + * @param callback */ - virtual bool startRequest() + void onRequest(const Callback &callback) { - // ok if no callback was set - if (!_start) return true; - - // call the callback function - return _start(this); + // copy callback + _onRequest = callback; } /** - * End a request + * Register a callback that is called to cleanup things after a pageview/request * - * This method is called when the Zend engine is ready with a request. - * Internally, it destructs the request - * - * @return boolean + * 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. + * + * @param callback */ - virtual bool endRequest() + void onCleanup(const Callback &callback) { - // ok if no callback is set - if (!_stop) return true; - - // call callback - return _stop(this); + // copy callback + _onCleanup = callback; } /** @@ -163,6 +151,31 @@ private: _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 _onReady; + + /** + * Callback that is called in front of each request + * @var Callback + */ + Callback _onRequest; + + /** + * Callback that is called right after each request + * @var Callback + */ + Callback _onCleanup; + + /** + * Callback that is called right before the engine is closing down + * @var Callback + */ + Callback _onFinalize; + + /** * Callback that is called before each request * @var request_callback */ |