php 调用 C 代码的方法详解和 zend_parse_parameters 函数详解
在 php 程序中需要用到 C 代码,应该是下面两种情况: 1 已有 C 代码,在 php 程序中想直接用 2 由于 php 的性能问题,需要用 C 来实现部分功能 针对第一种情况,最合适的方法是用 system 调用,把现有 C 代码写成一个独立 的
程序.参数通过命令行或者标准输入传入,结果从标准输出读出.其次,稍麻 烦一点的方法是 C 代码写成一个 daemon,php 程序用 socket 来和它进行通讯. 重点讲讲第二种情况,虽然沿用 system 调用的方法也可以,但是想想你的目的 是优化性能,那么频繁的起这么多进程,当然会让性能下降.而写 daemon 的方 法固然可行,可是繁琐了很多. 我的简单测试,同样一个算法,用 C 来写比用 php 效率能提高500倍.而用 php 扩展的方式,也能提高90多倍(其中的性能损失在了参数传递上了吧,我猜) . 所以有些时候 php 扩展就是我们的最佳选择了. 这里我着重介绍一下用 C 写 php 扩展的方法,而且不需要重新编译 php. 首先,找到一个 php 的源码,php4或者 php5版本的都可以,与你目标平台的 php 版本没有关系. 在 源 码 的 ext 目 录 下 可 以 找 到 名 为 ext_skel 的 脚 本 ( windows 平 台 使 用 ext_skel_win32.php) 在这个目录下执行./ext_skel --extname=hello(我用 hello 作为例子) 这时生成了一个目录 hello, 目录下有几个文件, 你只需要关心这三个: config.m4 hello.c php_hello.h 把这个目录拷备到任何你希望的地方,cd 进去,依次执行 (安装 phpize 等工具 yum -y install php-devel ) phpize ./configure
make 什么也没发生,对吧? 这是因为漏了一步,打开 config.m4,找到下面 dnl If your extension references something external, use with: ... dnl Otherwise use enable:
... 这是让你选择你的扩展使用 with 还是 enable,我们用 with 吧.把 with 那一部分 取消注释. 如果你和我一样使用 vim 编辑器, 你就会很容易发现 dnl 三个字母原来是表示注 释的呀(这是因为 vim 默认带了各种文件格式的语法着色包) 我们修改了 config.m4后,继续 phpize ./configure make 这时,modules 下面会生成 hello.so 和 hello.la 文件.一个是动态库,一个是静态 库. 你的 php 扩展已经做好了,尽管它还没有实现你要的功能,我先说说怎么使用这 个扩展吧!ext_skel 为你生成了一个 hello.php 里面有调用示例,但是那个例子需 要你把 hello.so 拷贝到 php 的扩展目录中去,我们只想实现自己的功能,不想打 造山寨版 php,改用我下面的方法来加载吧:
1 2 3 4 5
if(!extension_loaded("hello")) { dl_local("hello.so"); } function dl_local( $extensionFile ) { //make sure that we are ABLE to load libraries
6 7 8 9 10 11 12 13 14 15
if( !(bool)ini_get( "enable_dl" ) || (bool)ini_get( "safe_mode" ) ) { die( "dh_local(): Loading extensions is not permitted.\n" ); }
//check to make sure the file exists if( !file_exists(dirname(__FILE__) . "/". $extensionFile ) ) { die( "dl_local(): File '$extensionFile' does not exist.\n" ); } //check the file per
missions if( !is_executable(dirname(__FILE__) . "/". $extensionFile ) ) { die( "dl_local(): File '$extensionFile' is not
executable.\n" ); 16 } 17 //we figure out the path
18 19 20 21 22 23 24
$currentDir = dirname(__FILE__) . "/"; $currentExtPath = ini_get( "extension_dir" ); $subDirs = preg_match_all( "/\//" , $currentExtPath , $matches ); unset( $matches ); //lets make sure we extracted a valid extension path if( !(bool)$subDirs ) { die( "dl_local(): Could not determine a valid extension
path [extension_dir].\n" ); 25 } 26 $extPathLastChar = strlen( $currentExtPath ) - 1;
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
if( $extPathLastChar == strrpos( $currentExtPath , "/" ) ) { $subDirs--; } $backDirStr = ""; for( $i = 1; $i <= $subDirs; $