用C扩展PHP[转]

来源:互联网 发布:java调用windows api 编辑:程序博客网 时间:2024/04/29 11:35

来源:http://www.laruence.com/2008/08/16/301.html http://www.laruence.com/2009/04/28/719.html

有一个C/C++的库, 不妨假设,这个库呢就是实现了一个字符串加密和解密,而你并没有这个库的源码,也就是说,你无法把这个库在PHP中实现, 那么你只有编写一个PHP扩展,来做为一个桥梁,连接起你的PHP和这个库。效率, 不容置疑,PHP编写的脚本,比同等的C/C++编写的脚本,效率要高出很多。 当你用常见的手段,再也无法提高你的脚本的效率,而效率要求又是那么的紧迫, 那么我只能劝你, 把你的逻辑,用C/C++改写吧。

其实第二个理由,已经是很充足了,但是用扩展来实现你的逻辑,并不是那么简单的事情:首先如果你是使用PHP来实现你的逻辑,那么你不需要考虑资源管理,Zend会替你完成。其次你也不需要担心, 代码的一个简单的错误,就会导致PHP core dump。

而如果你用C来编写PHP的扩展,那么你就要自己考虑这些事情,自己管理资源的分配,使用,释放。 你也要学会适应segmentation fault 。 我要提醒你的是, 因为PHP是一个长时间运行的模块(因为Apache是一个长时间运行的Web服务器), 所以,你千万要防止资源泄露, 我就遇到过一个简单的字符串泄露, 在一段时间以后,Apache占用的内存超过了1个G。
接下来,总结一下用C/C++扩展PHP的优缺点:

优点:
效率,还是效率.减少PHP脚本的复杂度, 极端情况下, 你只需要在PHP脚本中,简单的调用一个扩展实现的函数,然后你所有的功能都就被扩展实现了。

缺点:
开发复杂、可维护性降低、开发周期变长, 最简单的一个例子,当你用PHP脚本的时候, 如果你发现某个判断条件出错,你只要修改了这一行,保存,那么就立刻能见效。 而如果是在C/C++编写的PHP扩展中, 那你可需要,修改源码,重新编译,然后重新load进PHP, 然后重启Apache,才能见效。

在php源码包目录下进入ext目录
touch myfunctions.def
vim myfunctions.def
添加如下内容
string self_concat(string str, int n)
保存退出
./ext_skel –extname=myfunctions –proto=myfunctions.def
cd myfunctions

在这个目录下,我们要尤其关注的是example.c这个文件,这个文件是我们扩展的主要文件,也就是说,如果我们要充实我们的扩展,那么就需要在这个文件中进行工作。 在后面的内容中,我会消息介绍这个文件中包含的各个字段,结构的含义,现在我们就只是简单的掠过他。
第二个要特别注意的文件就是config.m4,如果读者你有过在Unix/Linux下的编程经历,那么你或许听过autoconf和m4, m4是一个宏解释工具,它会把输入文件中的宏展开到输出文件。所以这个config.m4是PHP扩展框架所必须的,也是关键的一个文件,用来生成我们扩展的makefile。
CREDITES 这个文件没什么太大的作用,只是用来在发布你的扩展的时候附加一些其他信息 ,比如作者啊,等等。
EXPERIMENTAL 这个文件只是标志说,这个扩展是实验性的,所以你可以不用管它
example.php 这个文件是用来简单测试你的扩展的
php_example.h 这个是我们扩展的头文件
tests/001.phpt 这个也是个测试文件, 不过使用的是单元测试, 阶段测试, 具体内容,你打开一看便知 ;)

修改config.m4文件
去掉下面两行的注释
PHP_ARG_ENABLE(myfunctions, whether to enable myfunctions support,

[ --enable-myfunctions Include myfunctions support])
保存退出
接下来编译该扩展
/usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config
make && make install
在php.ini中添加 extension = myfunctions.so;
service php-fpm restart
查看phpinfo你会发现myfunctions扩展成功安装
下面你就可以扩展你自己的函数了
修改myfunctions.c 找到
PHP_FUNCTION(self_concat)
{}
将该函数替换为

view plaincopy to clipboardprint?
  1. PHP_FUNCTION(self_concat)  
  2. {  
  3. char *str = NULL;  
  4.   
  5. int argc = ZEND_NUM_ARGS();  
  6.   
  7. int str_len;  
  8.   
  9. long n;  
  10.   
  11. char *result; /* Points to resulting string */  
  12.   
  13. char *ptr; /* Points at the next location we want to copy to */  
  14.   
  15. int result_length; /* Length of resulting string */  
  16.   
  17. if (zend_parse_parameters(argc TSRMLS_CC, "sl", &str, &str_len, &n) == FAILURE)  
  18.   
  19. return;  
  20.   
  21. /* Calculate length of result */  
  22.   
  23. result_length = (str_len * n);  
  24.   
  25. /* Allocate memory for result */  
  26.   
  27. result = (char *) emalloc(result_length + 1);  
  28.   
  29. /* Point at the beginning of the result */  
  30.   
  31. ptr = result;  
  32.   
  33. while (n--) {  
  34.   
  35. /* Copy str to the result */  
  36.   
  37. memcpy(ptr, str, str_len);  
  38.   
  39. /* Increment ptr to point at the next position we want to write to */  
  40.   
  41. ptr += str_len;  
  42.   
  43. }  
  44.   
  45. /* Null terminate the result. Always null-terminate your strings 
  46.  
  47. even if they are binary strings */  
  48.   
  49. *ptr = '\0';  
  50.   
  51. /* Return result to the scripting engine without duplicating it*/  
  52.   
  53. RETURN_STRINGL(result, result_length, 0);  
  54. }  

重新编译该扩展
make && make install && service php-fpm restart
在测试文件中对该函数进行测试

view plaincopy to clipboardprint?
  1. #var_dump(get_loaded_extensions());  
  2. echo  confirm_xhg_compiled("myfunctions.so");  
  3. echo "\n\r";  
  4. for ($i = 1; $i <= 3; $i++){  
  5.      print self_concat("ThisIsUseless",$i);  
  6.      print "\n\r";  
  7. }  


转自http://blog.iterse.com/archives/721
原创粉丝点击