summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-08 19:36:16 +0100
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-08 19:36:16 +0100
commit25e162cbf64763245def4d11b4be40ced11ee330 (patch)
tree0d134472991c19278525bfc0c2e4cbeebca8dca2
parent8b64e27a4ac8000c08d154b6343cf6bcd537a014 (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.html2
-rw-r--r--documentation/extension-lifetime.html113
-rw-r--r--documentation/variables.html46
-rw-r--r--include/extension.h115
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 &lt;phpcpp.h&gt;
+#include &lt;iostream&gt;
+
+/**
+ * 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 &lt;&lt; array("Y-m-d H:i:s") &lt;&lt; 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 &lt;&lt; Php::GLOBALS["b"] &lt;&lt; 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
*/