In this short post we will quickly see:
- How to write PHP extensions?
- Why to write PHP extensions?
However before you could understand what we are going to disucss, I will recommend you to read one of my previous post How does PHP echo’s a “Hello World”? – Behind the scene . In this post I discussed in brief the backend architecture of PHP.
Assuming you have read the previous post, lets discuss on how to build our first PHP extension:
- Every PHP extension is built out of minimum of 2 files.
- Configuration file (config.m4) which tells us what files to build and what external libraries are needed.
- Source File(s) which will contain the actual functionalities provided by the extension.
Building a sample extension skeleton
Lets start with building and understanding a sample extension skeleton. Then we will move ahead with building our first PHP extension:
config.m4
PHP_ARG_ENABLE(sample,
[Whether to enable the "sample" extension],
[-enable-sample Enable "sample" extension support])
if test $PHP_SAMPLE != "no"; then
PHP_SUBST(SAMPLE_SHARED_LIBADD)
PHP_NEW_EXTENSION(sample,sample.c,$ext_shared) // 1st argument declares the module
// 2nd tells what all files to compile
// $ext_shared is counterpart of PHP_SUBST()
fi
I found a number of articles on internet which gives you code for your first PHP extension but none of them go ahead and explain each and every word in those codes. Lets give an attempt in understanding every bit of this strange config file.
- This is a minimalistic config file which is required for an extension
- The first parameter to PHP_ARG_ENABLE(), sets up a ./configure option called -enable-sample
- The second parameter to PHP_ARG_ENABLE() will be displayed during the ./configure process as it reaches this configuration file
- Third parameter will be displayed as an option if end user issues ./configure -help
For Newbies: Wondering what is this ./configure option? Kindly read PHP: Installation on Unix System for details.
Lets understand the remaining part of the config.m4 file:
- To compile an extension we follow 3 steps: (i) phpize (ii) ./configure -enable-sample (iii) make
- When we call ./configure -enable-sample in step (ii), a local environmental variable $PHP_SAMPLE is set to yes. (PS: If our extension name was Hello, then $PHP_HELLO would have been set to yes)
- PHP_SUBST() is a MACRO similar to AC_SUBST() in C and is necessary to build the extension as a shared module
- PHP_NEW_EXTENSION() declares the module and tell source files that must be compiled as part of the extension. $ext_shared is a counterpart of PHP_SUBST() and is necessary for buildin an extension as a shared module
(PS: We only have a single source file i.e. sample.c for this extension. If in case we had more than a single source file then last line of config.m4 would have been something like this: PHP_NEW_EXTENSION(sample,sample1.c sample2.c sample3.c,$ext_shared) and so on)
Now lets build our source file skeleton. Let’s segregate certain type of data in a header file, which we will finally include in sample.c file. This is generally a good practice rather than maintaining a single source file.
php_sample.h
#ifndef PHP_SAMPLE_H
#define PHP_SAMPLE_H
#define PHP_SAMPLE_EXTNAME "sample"
#define PHP_SAMPLE_EXTVER "1.0"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
extern zend_module_entry sample_module_entry;
#define phpext_sample_ptr &sample_module_entry
#endif
Do not leave this page on seeing this code. It’s all very simple if you have ever written some code in C.
All that this file wants to do is:
- config.h file is included when compiled using phpize tool
- It also includes php.h from the PHP source tree. With inclusion of php.h, many other .h files also gets included and hence making available a lot of PHP API’s, which can be used by this extension
- The zend_module_entry struct is defined as extern so that it can be picked up by ZEND engine using dlopen() and dlsym() functions, when the module loads.
sample.c
#include "php_sample.h"
zend_module_entry sample_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER, // Roughly means if PHP Version > 4.2.0
#endif
PHP_SAMPLE_EXTNAME, // Define PHP extension name
NULL, /* Functions */
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
PHP_SAMPLE_EXTVER, // Roughly means if PHP Version > 4.2.0
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_SAMPLE
ZEND_GET_MODULE(sample) // Common for all PHP extensions which are build as shared modules
#endif
Thats it! We have our first PHP extension ready. Compile this module as discussed above i.e.
(i) phpize
(ii) ./configure -enable-sample
(iii) make
check your phpinfo() and see if you have an extension called “sample” loaded successfully or not.
Though this extension is capable of doing nothing, but the skeleton here is the base for every PHP extension. Lets recap in short what has happened till now:
RECAP
- config.m4 file is the configuration file for extension
- It declared the extension, tells what all files are required for the extension to build, add a few ./configure -help options too
- On the other hand sample.c and php_sample.h are the main source files.
- The header file includes the config.h and php.h header files from PHP source tree, which additionally provides a number of PHP API’s which can be used
- As discussed in last blog post, every extension have the following modules: MINIT, RINIT, RSHUTDOWN, MSHUTDOWN. sample.c helps in telling PHP, which part of the code corresponds to the above module
- For our extension “sample” we have defined NULL as MINIT, RINIT, RSHUTDOWN and MSHUTDOWN and hence this module isn’t capable of doing anything
Building a Hello World Extension
To build an extension which actually do something, we will need to just tweak the abiove skeleton. Here we are trying to build an extension which will provide us with a function called sample_hello_world(), which we can use directly in our php codes to output Hello World!
Quickest link between userspace and extension code is the PHP_FUNCTION(). Start by adding the following code block near the top of sample.c file just after
#include “php_sample.h”
PHP_FUNCTION(sample_hello_world) {
php_printf("Hello World!\n");
}
PHP_FUNCTION() is basically a MACRO which expands internally. (I will skip this expansion as of now to keep this post as simple as possible)
But simply declaring the function isn’t enough. The ZE needs to know the address of the function as well as how the function name should be exported to the userspace. Place the following block of code immediately after PHP_FUNCTION() block:
static function_entry php_sample_functions[] = {
PHP_FE(sample_hello_world,NULL)
{NULL,NULL,NULL}
};
The php_sample_functions vector is a NULL terminated vector that will grow as we continue to add more functionality to sample extension. Every function we export will appear as an item in this vector.
PHP_FE(sample_hello_world,NULL) expands to {sample_hello_world, zif_sample_hello_world, NULL} and hence providing a name and an address to implement it.
Finally simply go to the sample_module_entry struct and replace:
NULL /* functions */ with
php_sample_functions /* functions */
Now simply rebuild the extension and then try this on command line:
$ php -r ’sample_hello_world();’
If everything was done perfectly, you would see “Hello World!” output on the shell.
PS: In this tutorial I have tried to explain each and every line which is involved in making a hello world php extension. However I am sure that many questions are still un-answered. Feel free to ask any doubt or correct me in case I have made a blunder while penning this down.
Abhi's Weblog is a collection of blog articles written by
[...] PHP Extensions – How and Why? | Abhi's Weblog (tags: php) December 11th, 2008 Posted in ???? This entry was posted on Thursday, December 11th, 2008 at 1:02 pm and is filed under ????. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site. [...]
[...] WebPage Test 20-excellent-ajax-effects-you-should-know Build PHP Extension Possibly related posts: (automatically generated)PHP Ajax FrameworksGood PHP tutorials at my [...]
[...] PHP Extensions – How and Why? | Abhi's Weblog Because you can (tags: programming php tutorials extension) [...]
Great explanation on the how, but why would I want to create an extension?
I’m getting into deeper PHP coding recently and love learning about all of this low-level stuff. I just don’t understand the why.
Thanks again for a great article.
Sorry for missing out the why part towards the end. Lemme summarize it in 2-3 lines. You may want to write PHP extensions for following reasons:
1. PHP extensions are written in C, and pre-compiled. Hence you get faster response for your functions. For eg. We have mysql extension enabled which allows us to connect to mysql database. Since we know that connecting to a mysql db is a common thing, hence we wrote an extension for it. To save time.
2. Secondly you may be interested in writing an extension because you don’t want your code to be read by others. Suppose you developed some algorithm or implemented a great algo. Now you want the world to use it but you are still not prepared to open it up. Simple enough, just create an extension out of your php code and distribute the .so file across the world.
3. Finally you may want to create PHP extensions if you are mad like me, for no reasons ofcourse
Regards,
Abhi
do you have some books recommendations to continue the study of php extensions ?
almost forgot, great article
Thanks. Well there must be some great books on this issue. However since I mostly read from my internal office network twiki, I am not aware of any names.
Try to search on safari and you will find plenty. All the best.
I think the barrier for entry for me is figuring out how to debug memory crashes. Several tutorials have pointed out linking to the PHP executable in VS, but I’m unsure how this will work.
Oh yeah, how do you debug PHP extensions on Windows? I think that would be an awesome blog post. Preferably, using Visual Studio Express or 2005/2008.
@Jacob Santos
Hi Jacob, I know there is a lot more to writing PHP extensions. One need to have all internals knowledge including ZVAL etc for writing a good extension. I am planning one of my next posts on the same topic.
Regarding debugging PHP extensions on windows, well I wasn’t able to setup the environment for that on my local windows
I remember I needed a few stuffs and couldn’t find them. Will appreciate if someone else can write one on that
Belated Merry Christmas and Happy New Year
I plan on working on my PHP extension in February to see if I can get it debugged. If I can get it working by linking against the PHP executable, then I’ll be sure to write a blog post.
It is super annoying not being able to step through code.
Yeah I did tried coming up with extension.dll on windows system but for some reasons I wasn’t able to crack through. Will appreciate a step through tutorial for the same.
I need more explanation.
Can you kindly be more specific as to what are you referring to. More explaination on what?
i wanna to make it work for me. where should i store these files to run??? inside PHP?
Hi Ramya,
[...] Engine: Below are 3 very useful PHP extensions for geeky PHP developers. (Specially helpful for all PHP extension [...]
COMPILE_DL_* is defined by the PHP_NEW_EXTENSION macro and supposedly written to config.h so that the code being compiled can see it – and can export the _get_module symbol correctly which is absolutely required for a shared module.
However I even built PHP 5.3.0 and a few standard modules (as shared, of course) successfully under Fedora 9 but still there was no config.h in the source tree. After a few days of hacking I found everything in php_config.h. Which is included automatically as php.h – php_compat.h – php_config.h.
Conclusion: the whole HAVE_CONFIG_H mechanism is outdated and not used any more.
Hi Saimhe,
Absolutely right.
There are a lot of changes being made to the PHP API’s for building extensions.
- Abhi
[...] Engine: Below are 3 very useful PHP extensions for geeky PHP developers. (Specially helpful for all PHP extension [...]