summaryrefslogtreecommitdiff
path: root/documentation/loading-extensions.html
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-05 12:13:54 +0100
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-05 12:13:54 +0100
commit902d86acbe01b0368771eb57873e09f2cfcd8184 (patch)
tree915525263b9c6ecf7aebaffcd46e5a82f735f37d /documentation/loading-extensions.html
parented200cc18fb5fea88b8e9e2ff730af6cf1d50663 (diff)
default empty extension added, optimized Makefile
Diffstat (limited to 'documentation/loading-extensions.html')
-rw-r--r--documentation/loading-extensions.html286
1 files changed, 286 insertions, 0 deletions
diff --git a/documentation/loading-extensions.html b/documentation/loading-extensions.html
new file mode 100644
index 0000000..2556efd
--- /dev/null
+++ b/documentation/loading-extensions.html
@@ -0,0 +1,286 @@
+<div style="width: 1024px; font-family: verdana; font-size: 10pt; line-height: 16pt;">
+
+
+<h1>How does PHP load its extensions?</h1>
+<p>
+ You probably already know that native PHP extensions are compiled into *.so
+ files on unix-like systems, and *.dll files in Windows environments, and that
+ the global php.ini file holds a list of all extensions available on your system.
+ This means that if you're building your own extension, you are also going to
+ create such a *.so or *.dll file and you have to update the PHP
+ configuration file so that your own extension is loaded by PHP.
+</p>
+<h3>Where to find your PHP configuration files?</h3>
+<p>
+ If for one reason or another you can not find the PHP configuration file(s)
+ on your system, you can run the following command from the command line:
+</p>
+<p>
+ <code><pre>
+ php --ini
+ </pre></code>
+</p>
+<p>
+ This will output a list of all configuration files that are loaded by PHP.
+ Extensions are enabled by adding "extension=name.so" lines to the
+ configuration file - where 'name' should of course be replaced by the name of
+ your extension. A default PHP installation already comes with many default
+ extensions, so in the configuration file(s) on your system you will certainly
+ find a number of these "extension=name.so" lines.
+</p>
+<p>
+ The extension lines either take an absolute path ("extension=/path/to/extension.so")
+ or a relative path ("extension=extension.so"). If you'd like to use relative
+ paths, you must make sure that you've copied your extension *.so file to the
+ default extension directory, so that PHP can find it. To find out this default
+ extension directory, use the following command line instruction:
+</p>
+<p>
+ <code><pre>
+ php -i|grep extension_dir
+ </pre></code>
+</p>
+<p>
+ The extension dir often has the form /usr/lib/php5/20121212 - or a different
+ date string depending on the PHP version you use.
+</p>
+
+<h2>The get_module() startup function</h2>
+<p>
+ Before we explain how you can create your own extension, we first explain
+ what PHP does to load an extension. When PHP starts, it loads the *.ini configuration
+ file(s) that we just described and for each "extension=name.so" line in these
+ files, it opens the appropriate library, and calls the "get_module()"
+ function from it. Each extension library (your extension too) must therefore
+ define and implement this "get_module()" C function. The function is called by
+ PHP right after the library is loaded (and thus way before pageviews are handled),
+ and it should return a memory address that points to a structure that holds information
+ about all functions, classes, variables and constants that are made available
+ by the extension.
+</p>
+<p>
+ The structure that the get_module() returns is defined in the header files of
+ the Zend engine, but it is a pretty complicated structure without good documentation.
+ Luckily, the PHP-CPP library makes life easier for you, and offers an Extension
+ class that can be used instead.
+</p>
+<p>
+ <code><pre>
+ #include &lt;phpcpp.h&gt;
+
+ /**
+ * tell the compiler that the get_module is a pure C function
+ */
+ extern "C" {
+
+ /**
+ * Function that is called by PHP right after the PHP process
+ * has started, and that returns an address of an internal PHP
+ * strucure with all the details and features of your extension
+ *
+ * @return void* a pointer to an address that is understood by PHP
+ */
+ PHPCPP_EXPORT void *get_module()
+ {
+ // static(!) Php::Extension object that should stay in memory
+ // for the entire duration of the process (that's why it's static)
+ static Php::Extension myExtension("my_extension", "1.0");
+
+ // @todo add your own functions, classes, namespaces to the extension
+
+ // return the extension
+ return myExtension;
+ }
+ }
+ </pre></code>
+</p>
+<p>
+ In the example above you see a very straightforward implementation of the
+ get_module() function. Every PHP extension that uses the PHP-CPP library
+ implements this function in a more or less similar way, and it is the
+ starting point of each extension. A number of elements require special attention.
+ For a start, the only header file that you see is the phpcpp.h header
+ file. If you're using the PHP-CPP library to build your own extensions,
+ you do not have to include the complicated, unstructured, and mostly undocumented
+ header files of the Zend engine - all you need is this single phpcpp.h header
+ file of the PHP-CPP library. If you insist, you are of course free to also
+ include the header files of the core PHP engine - but you do not have to.
+ PHP-CPP takes care of dealing with the internals of the PHP engine, and offers
+ you a simple to use API.
+</p>
+<p>
+ The next thing that you'll notice it that we placed the get_module() function
+ inside an 'extern "C"' code block. As the name of the library already gives away,
+ PHP-CPP is a C++ library. However, PHP expects your library, and especially your
+ get_module() function, to be implemented in C and not in C++. That's why we've
+ wrapped the get_module() function in an 'extern "C"' block. This will instruct
+ the C++ compiler that the get_module() is a regular C function, and that it
+ should not apply any C++ name mangling to it.
+</p>
+<p>
+ The PHP-CPP library defines a "PHPCPP_EXPORT" macro that should be placed
+ in front of the get_module() function. This macro makes sure that the get_module()
+ function is publicly exported, and thus callable by PHP. The macro has a different
+ implementation based on the compiler and operating system.
+</p>
+<p>
+ This, by the way, is also the only macro that PHP-CPP offers. PHP-CPP intends to
+ be a very straightforward C++ library, without using magic or tricks from
+ pre-processors. What you see is what you get: If something looks like a
+ function, you can be sure that it actually IS a function, and when something
+ looks like a variable, you can be sure that it also IS a variable.
+</p>
+<p>
+ Let's move on. Inside the get_module() function the Php::Extension object is
+ instantiated, and it is returned. It is crucial that you make a <i>static</i>
+ instance of this Php::Extension class, because the object must exist for the
+ entire lifetime of the PHP process, and not only for the duration of the get_module()
+ call. The constructor takes two arguments: the name of your extension and
+ its version number.
+</p>
+<p>
+ The final step in the get_module() function is that the extension object
+ is returned. This may seem strange at first, because the get_module() function
+ is supposed to return a pointer-to-void, and not a full Php::Extension object.
+ Why does the compiler not complain about this? Well, the Php::Extension class
+ has a cast-to-void-pointer-operator. So although it seems that you're returning
+ the full extension object, in reality you only return a memory address that
+ points to a data structure that is understood by the core PHP engine and that
+ holds all the details of your extension.
+</p>
+<p>
+ Note that the example above does not yet export any native functions or
+ native classes to PHP - it only creates the extension. That is going to be
+ the next step.
+</p>
+
+
+
+<h2>Exporting native functions</h2>
+<p>
+ An extension can of course only be useful if you define functions and/or
+ classes that can be accessed from PHP scripts. For functions you can do this
+ by adding your native function implementations to the Extension object:
+</p>
+<p>
+ <code><pre>
+ #include &lt;phpcpp.h&gt;
+
+ extern void example1();
+ extern void example2(Php::Parameters &amp;params);
+ extern Php::Value example3();
+ extern Php::Value example4(Php::Parameters &amp;params);
+
+ extern "C" {
+ PHPCPP_EXPORT void *get_module() {
+ static Php::Extension myExtension("my_extension", "1.0");
+ myExtension.add("native1", example1);
+ myExtension.add("native2", example2);
+ myExtension.add("native3", example3);
+ myExtension.add("native4", example4);
+ return myExtension.module();
+ }
+ }
+ </pre></code>
+</p>
+<p>
+ What do we see here? We've added four function declarations ("example1",
+ "example2", "example3" and "example4") to the source code of our extension.
+ The reason why we've only declared the functions, and not fully implemented
+ them is to keep the example code relatively small. We assume that the
+ four example functions are implemented in a different file. In a real world
+ example you could just as well remove the "extern" keyword and implement the
+ four functions in the same source file as the get_module() call.
+</p>
+<p>
+ The four functions all have a different signature: Some return a value, while
+ others do not return anything. And some take parameters, while others do not.
+ Despite the different signature of the functions, they can all be made
+ available in PHP by adding them to the extension object, by simply calling
+ the myExtension.add() method. This method takes two parameters: the name by
+ which the function should be accessible in PHP, and the actual native
+ function.
+</p>
+<p>
+ In the example above we've used different names for the native functions
+ ("example1" up to "example4") as for the PHP functions ("native1" to
+ "native4"). This is legal - you do not have to use the same names for your
+ native functions as for your PHP functions. The following PHP script can be
+ used to call the four native functions:
+</p>
+<p>
+ <code><pre>
+ &lt;?php
+ native1();
+ native2("a","b");
+ $x = native3();
+ $y = native4(1,2);
+ ?&gt;
+ </pre></code>
+</p>
+<p>
+ It is not possible to export every thinkable C/C++ function to the
+ PHP extension. Only functions that have one of the four supported signatures
+ can be exported: functions that return
+ void or a Php::Value object, and that either accept a Php::Parameters object
+ or no parameters at all, can be added to the extension object and can thus
+ be exported to PHP.
+</p>
+<h2>Parameter types</h2>
+<p>
+ PHP has a mechanism to enforce function parameters types, and to accept
+ parameters either by reference or by value. In the examples above, we have
+ not yet used that mechanism yes: it is up to the function implementations
+ themselves to inspect the 'Parameters' object, and check if the
+ variables are of the right type.
+</p>
+<p>
+ However, the 'Extension::add()' method takes a third optional parameter that
+ you can use to specify the number of parameters that are supported, whether
+ the parameters are passed by reference or by value, and what the type of
+ the parameters is:
+</p>
+<p>
+ <code><pre>
+ #include &lt;phpcpp.h&gt;
+
+ extern void example(Php::Parameters &amp;params);
+
+ extern "C" {
+ PHPCPP_EXPORT void *get_module() {
+ static Php::Extension myExtension("my_extension", "1.0");
+ myExtension.add("example", example, {
+ Php::ByVal("a", Php::Type::Numeric),
+ Php::ByVal("b", "ExampleClass"),
+ Php::ByRef("c", "OtherClass")
+ });
+ return myExtension.module();
+ }
+ }
+ </pre></code>
+</p>
+<p>
+ Above you see that we passed in additional information when we registered the
+ "example" function. We tell our extension that our function accepts three parameters:
+ the first parameter must be a regular number, while the other ones are object
+ instances of type "ExampleClass" and "OtherClass". In the end, your native C++
+ "example" function will still be called with a Php::Parameters instance, but
+ the moment it gets called, you can be sure that the Php::Parameters object
+ will be filled with three members, and that two of them are objects of the
+ appropriate type, and that the third one is also passed by reference.
+</p>
+<h2>Working with variables</h2>
+<p>
+ Variables in PHP are non-typed. A variable can thus hold any possible type:
+ an integer, string, a floating point number, and even an object or an array.
+ C++ on the other hand is a typed language. In C++ an integer variable always
+ has a numeric value, and a string variable always hold a string value.
+</p>
+<p>
+ When you mix native code and PHP code, you will need to convert the non-typed
+ PHP variables into native variables, and the other way round: convert native
+ variables back into non-typed PHP variables. The PHP-CPP library offers the
+ "Value" class that makes this a very simple task.
+</p>
+<p>
+ \ No newline at end of file