C code needs to be used in the php program, which should be the following two situations:
1 I already have C code and want to use it directly in the PHP program
2 Due to performance issues with PHP, I need to use C to implement some functions
For the first situation, the most appropriate method is to use system calls to write the existing C code into an independent program. Parameters are passed in through the command line or standard input, and the results are read from standard output. Secondly, the slightly more troublesome method is to write C code as a daemon, and the PHP program uses socket to communicate with it.
Focus on the second case. Although it is also possible to use the system call method, consider that your purpose is to optimize performance. Starting so many processes so frequently will of course degrade performance. The method of writing a daemon is certainly feasible, but it is much more complicated.
My simple test shows that the same algorithm is 500 times more efficient when written in C than in PHP. And using PHP extension can also improve it by more than 90 times (the performance loss is in parameter passing, I guess).
So sometimes php extension is our best choice.
Here I will focus on how to write PHP extensions in C without recompiling PHP.
First of all, find a php source code. It can be php4 or php5 version. It has nothing to do with the php version of your target platform.
You can find a script named ext_skel in the ext directory of the source code (windows platform uses ext_skel_win32.php)
Execute ./ext_skel --extname=hello in this directory (I use hello as an example)
At this time, a directory hello is generated. There are several files in the directory. You only need to care about these three: config.m4 hello.c php_hello.h
Copy this directory to wherever you want, cd into it, and execute
phpize
/configure
make
in sequence. Nothing happens, right?
This is because you missed a step. Open config.m4 and find the following
dnl If your extension references something external, use with:
..
dnl Otherwise use enable:
..
This allows you to choose whether your extension uses with or enable. Let’s use with. Uncomment the with part.
If you use the vim editor like me, you will easily find that the three letters dnl originally represent comments (this is because vim comes with syntax coloring packages for various file formats by default)
After we modify config.m4, continue
phpize
/configure
make
At this time, hello.so and hello.la files will be generated under modules. One is a dynamic library and the other is a static library.
Your php extension is ready, although it has not yet achieved the function you want. Let me first talk about how to use this extension! ext_skel generated a hello.php for you with a calling example, but that example requires you to copy hello.so to the extension directory of PHP. We just want to implement our own functions and don't want to create a copycat version of PHP. Instead, use the following To load it:
The next question that people are concerned about is how to add functions, implement parameter transfer and return values
The steps to add a function are as follows:
php_hello.h:
PHP_FUNCTION(confirm_hello_compiled);// Fill in the function name in the brackets
hello.c
zend_function_entry hello_functions[] = {
PHP_FE(confirm_hello_compiled, NULL) /* Add a line here*/
{NULL, NULL, NULL} /* Must be the last line in hello_functions [] */
};
PHP_FUNCTION(confirm_hello_compiled)
{// Write the function body here
}
The function prototypes to be implemented are actually the same, and they are packaged with the macro PHP_FUNCTION , In addition, a line of information is added to hello_functions, indicating that you have this function in this module.
So they all have the same function prototype, how to distinguish the return value and parameters?
I will give you an example:
把这个当成是scanf来理解好了。
类型说明见下表:
Boolean | b |
zend_bool |
Long | l |
long |
Double | d |
double |
String | s |
char*, int |
Resource | r |
zval* |
Array | a |
zval* |
Object | o |
zval* |
zval | z |
zval* |
如果想实现可选参数的话,例如一个字符串,一个浮点,再加一个可选的bool型,可以用"sd|b"来表示。
和scanf有一点不同的是,对于字符串,你要提供两个变量来存储,一个是char *,存字符串的地址,一个int,来存字符串的长度。这样有必要的时候,你可以安全的处理二进制数据。
那么返回值怎么办呢?
使用下面一组宏来表示:
RETURN_STRING
RETURN_LONG
RETURN_DOUBLE
RETURN_BOOL
RETURN_NULL
注意RETURN_STRING有两个参数
当你需要复制一份字符串时使用
RETURN_STRING("Hello World", 1);
否则使用
RETURN_STRING(str, 0);
这里涉及到了模块中内存的分配,当你申请的内存需要php程序中去释放的话,请参照如下表
Traditional | Non-Persistent | Persistent |
---|---|---|
malloc(count) calloc(count, num)
|
emalloc(count) ecalloc(count, num)
|
pemalloc(count, 1) *pecalloc(count, num, 1)
|
strdup(str) strndup(str, len)
|
estrdup(str) estrndup(str, len)
|
pestrdup(str, 1) pemalloc() & memcpy()
|
free(ptr) |
efree(ptr) |
pefree(ptr, 1) |
realloc(ptr, newsize) |
erealloc(ptr, newsize) |
perealloc(ptr, newsize, 1) |
malloc(count * num + extr) **
|
safe_emalloc(count, num, extr) |
safe_pemalloc(count, num, extr) |
Generally we use the ones listed in Non-Persistent.
That’s basically it, you can start writing a php extension.
From my current application point of view, being able to manipulate strings is enough, so I can only introduce so much.