PHP Native Interface
PHP Native Interface (PNI) is a PHP extension that enables PHP code to call and be called by native applications (programs specific to a hardware and operating system platform) and libraries written in other languages such as C, C++ and assembly..
It resembles Java Native Interface (JNI).
OutlinePurpose & FeaturesSituations
PNI allows programmers to use native code when an application cannot be written entirely in the PHP language. The following are typical situations where you might decide to use native code:
Compared with PHP Extension
As all PHPers known, It is a tranditional way to call C/C++ that to write PHP extension. However, PNI has multiple virtues:
Reduce maintenance cost
It’s a risk of restarting the PHP service when install or update a new PHP extension, especially while operating the PHP cluster. But with PNI, we just change the local interface library.
Reduce development cost
Compared with developing PHP extension , developing native interface just like write native C/C++.
Reduce learning cost
Developers has no need to learn the PHP-API, Zend-API or PHP extension framework any more. Data types and PNI framework are more simple.
Flexible
PHP-API and Zend API are also available in native interface.
Scalable
Increasing native interface has no effect on current PHP service.
PitfallsTutorial & Examples1.Write the C/C++ code
// file pni_math.c#include<math.h>#zval *PNI_pow(zval **args) { // every PNI function returns zval(php variable) , the paramters are in the argsdouble x,y,z;zval *tmp = NULL;zval *res = NULL;tmp = args[0];x = Z_DVAL_P(tmp); // get the double value via Z_DVAL_Ptmp = args[1];y = Z_DVAL_P(tmp); // Why we write it like this instead of `y = Z_DVAL_P(args[1]);`? It’s a C Trap.z = (res, z); // Use ZVAL_DOUBLE to assign the result to the return variable, the data type is double.return res;}
2.Create the shared library file and move it to the directory which$LD_LIBRARY_PATHcontains.
php-ni -lm -o libpnimath.so pni_math.c
3.Create PHP code
{(PNI_pow((unDefinedFunction() {(
4.Run the PHP script
$ php testPni.php
the output as below
float(64)string(154) "Dlopen /unexisted/library.so error (/unexisted/library.so: cannot open shared object file: No such file or directory), dl handle resource is not created."string(69) "#0 /root/pni.php(5): PNI->__construct(‘/unexisted/libr…’)#1 {main}"
How to get data from zval?
All the operator macros are defined in the Zend APIs.
Z_LVAL_P(zval_p) // get Long(no int)Z_BVAL_P(zval_p) // get BooleanZ_DVAL_P(zval_p) // get DoubleZ_STRVAL_P(zval_p) // get char *Z_STRLEN_P(zval_p) // get the length of a string / Long
How to assign a value to the return variable
Thus the PNI function return variable is zval,first of all, you need to initialise it by usingALLOC_INIT_ZVAL(res). And then, assign the value to it.
ZVAL_NULL(z)// assign NULLZVAL_LONG(z, l) // assign LONGZVAL_STRING(z, s, duplicate)//assign a string/char * . Duplicate ? allways be 1.ZVAL_STRINGL(z, s, l, duplicate) //assign a string with fixed length. Duplicate ? the same as above.ZVAL_FALSE(z)ZVAL_TRUE(z)ZVAL_BOOL(z, boolean) // ZVAL_BOOL(z, 1) and ZVAL_TRUE(z) are the same.Likely, ZVAL_BOOL(z, 0) and ZVAL_FALSE(z) are the same.
It’s unnecessary to know more about Zend APIs or PHP APIs. All referred above is ample to help us achieve the simple communication between PHP code and C code.
RequirementsInstallationDownload the code source
git clone https://github.com/zuocheng-liu/pni.git
Complie the pni extension code
cd <src-pni>phpize./configuremake && make install
Make PNI work
add the line below to php.ini
extension=pni.so;
Restart PHP service
service php-fpm restart // cgi modeapachectl restart // sapi mode // do nothing in cli mode
DevelopmentReporting bugs and contributing code
Contributions to PNI are highly appreciated either in the form of pull requests for new features, bug fixes, or just bug reports.
OtherRelated linksSource codeAuthorZuocheng Liuzuocheng.liu@gmail.comLicense
The code for PNI is distributed under the terms of version 3.01 of the PHP license.(see LICENSE)
,坐在外婆的沙滩,看最白的帆影。