New Mind Blog
Tips, tricks and solutions for the web/mobile developer community.

BLOG TOPICS:
 
 
Blog
 
Bringing the open into open source.
 
 
Creating new, native PHP functions to leverage C++ in PHP
 
Category: Programming

Creating a native PHP function - that is, a function callable inside PHP code as though it is just another plain ol' native PHP function - involves surprisingly little effort. In this blog, I will present (almost) the shortest possible body of code that is required to create a PHP extension in C++ - that nonetheless passes the test as a legitimate PHP extension that plays by the rules.

As a word of background - almost all PHP functions have been implemented in C++, and almost all of these are contained in libraries (called PHP extensions) that reside in the ext directory in the main PHP installation. On Linux, these are shared object files (*.so), and on Windows, they are dynamic-link libraries (*.dll). For example, the MySQL connectivity functions such as mysql_connect() reside in one of the MySQL PHP extensions in the /ext directory.

Creating a new, native PHP function involves writing a new PHP extension. I show how to do it in C++. The skeleton code is shown here for an example PHP library which turns on the user's screen saver. For this example, the PHP libary will contain only one function that can be called from PHP - the function which turns on the user's screen saver. This function is called "scrsave_turnon" in the code below.

You must have the developer version of PHP installed on the system, which includes the "php.h" and "php_ini.h" files. These files define the macros "PHP_MINFO_FUNCTION", "PHP_MINIT_FUNCTION", "PHP_MSHUTDOWN_FUNCTION", and "PHP_FUNCTION", which export their arguments as externally-callable library functions and defines arguments to those functions that PHP needs.

Here is the C++ header file (scrsave.h):

#include "php.h"
#include "php_ini.h"
PHP_MINFO_FUNCTION(scrsave);
PHP_MINIT_FUNCTION(scrsave);
PHP_MSHUTDOWN_FUNCTION(scrsave);
PHP_FUNCTION(scrsave_turnon);

Now here's the C++ source file (scrsave.cpp):

#include "scrsave.h"

// list of functions available in PHP -
// used to provide module information, below
zend_function_entry guid_functions[] =
{
PHP_FE(scrsave_turnon, NULL) {NULL, NULL, NULL}
};

// PHP module information that php.exe will look for
zend_module_entry guid_module_entry =
{
STANDARD_MODULE_HEADER,
"scrsave",
guid_functions,
PHP_MINIT(scrsave),
PHP_MSHUTDOWN(scrsave),
NULL,
NULL,
PHP_MINFO(scrsave),
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES
};

//Tell php.exe to include this module
ZEND_GET_MODULE(scrsave)

// Be a good citizen and populate phpinfo()
PHP_MINFO_FUNCTION(scrsave)
{
php_info_print_table_start();
php_info_print_table_row(2, "Screensaver extension", "All Systems Go");
php_info_print_table_end();
}

// Initialize our PHP extension
PHP_MINIT_FUNCTION(scrsave)
{
// PHP is initializing
// Do anything you want here... such as querying the OS for information about the user's monitors
return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(scrsave)
{
// PHP is shutting down
// Clean up
return SUCCESS;
}

PHP_FUNCTION(scrsave_turnon)
{
// Aah! This is our native PHP function
// This function can be called from inside PHP code
// We can turn on the user's screen saver here

// Retrieve an argument that was been passed by PHP
long whichScreenSaver = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &whichScreenSaver) == FAILURE)
{
RETURN_STRING("Bad parameters!", true);
}

// This is the function that actually turns on their screensaver.
// Of course - this is just an example. Anything can happen here.
RunScreensaver(whichScreenSaver);

// Note the value here that is returned by us and received by PHP as a result of this function call
// ... it is wrapped by another macro provided by PHP
RETURN_STRING("Success!", true);
}

The line with PHP_FUNCTION() is the C++ function that is called from inside PHP. Anything you can do with C++, you can do inside this function. In order to access the arguments that were passed from PHP, call the "zend_parse_parameters()" function, as shown. The "l" (letter L) indicates that we expect a "long" variable from PHP. The options are: "l", "d", "s", "b", "r", "a", "o", "O", "z". The first four stand for "long", "double", "string" and "bool"; I won't discuss the others, but see the reference I provide below for more details. For strings, you must pass an additional argument to zend_parse_parameters() indicating the length of the buffer you've provided, as in 'zend_parse_parameters(..., "s", &s, &len_s)' (where "s" is a pre-allocated char* and len_s is an int containing the length of the buffer). You may also retrieve multiple arguments at a time - for example, 'zend_parse_parameters(..., "sdb", &s, &len_s, &d1, %b1)' (where d1 is a double and b1 is a boolean) will retrieve a string, double, and bool (in that order).

Build the extension, copy it into the /ext folder in your PHP installation, add the necessary line to include it in your PHP.ini file:
extension=php_scrsave.dll
(or .so for Linux)
... and then restart the web server and call the new native PHP function!

This blog has attempted to create a PHP extension using the smallest amount of code possible. I have not discussed powerful features of C++/PHP integration such as the "zval" variable, classes and objects ("o" and "O"), INI variables, or other features. For further and more detailed discussions, see http://dev​zone.zend.​com/articl​e/4486 and http://www​.hospedaje​ydominios.​com/mambo/​documentac​ion-manual​ _php-pagin​a-zend_arg​uments_ret​rieval.htm​l and http://dev​zone.zend.​com/articl​e/4486.

February 26, 2010 5:23am by dnissenbaum