PHP 扩展开发[从零开始编写第一个PHP扩展]

操作系统:Mac OS / Linux

在开始之前,应该先下载 PHP 源码,可到 http://php.net/get/php-5.6.12.tar.bz2/from/a/mirror 下载,这里选择的是中国的。下载之后解压,存放到自己喜欢的任何一个工作目录中,比如我这里是放在 Mac 桌面。另外,系统中需要安装有 C 的编译环境,另外还有 make 和 autoconf。因此,在 linux 中可以直接通过 sudo apt-get install gcc make autoconf来同时安装这三样东西。而在Mac中,只需要安装个 autoconf 就可以了,其他的系统自带, 可利用命令 sudo brew install autoconf 安装。


得到PHP源码之后,cd 进入该文件夹,里面有个 etx 文件夹,如下图所示:

PHP 扩展开发[从零开始编写第一个PHP扩展]_第1张图片

cd 进入该文件夹,ls 命令可看到etx_skel 文件,这个文件可以用来生成扩展模块,执行 ./ext_skel --extname=test 即可在该目录下创建一个叫 test 的扩展文件,cd test 进入后利用 ls 命令可看到一系列文件,如下图所示,其中 config.m4 是相关的扩展配置文件:



命令行中利用 sudo vim config.m4 打开,找到如下部分,去掉前面的 dnl 后保存, 结果如下所示(dnl 是在该文件中用于注释的):



接下来,直接在命令行中敲打 phpize,它会根据刚刚修改的 config.m4 生成一个 configure 脚本,之后执行该脚本,它便会继续生成一个 Makefile 文件, 具体如下:

PHP 扩展开发[从零开始编写第一个PHP扩展]_第2张图片

有了 Makefile 文件,我们便能通过 make 和 sudo make install 进行 C 源文件的编译。之后我们可以利用php -i | grep php.ini 找到 php.ini 这个配置文件的路径,在最后加上extension=test.so,表示开启 test 扩展。开启之后利用命令 php -m 检查一下,你会发现在列出来的所有 module 中存在一个叫 test 扩展。


继续之前的 sudo make install 编译之后,在 test 文件夹中我们可以看到 一个 php_test.h 文件和一个 test.c 文件。我们在写 C 的时候,可以在不同的文件中声明和定义一个函数,关键是需要在定义该函数的文件中 include 声明该函数的文件。而在PHP扩展中也一样,我们是在 PHP_test.h 中声明我们扩展的函数而在 test.c 中定义该函数。当然,php_test.h 和 test.c 这两个文件的命名是根据我们刚刚创建的扩展模块 test 命名的。


假设我们这里要实现一个函数的扩展,假设该函数名是 hello_world, 我们可以直接在 php_test.h 文件中利用如下语句声明该函数,PHP_FUNCTION 就类似 C 中的一个宏扩展。

<span style="font-size:14px;">PHP_FUNCTION(echo_hello_world);</span>


完成了该函数的声明之后,我们需要在 test.c 文件中定义该函数,假设我们定义的函数如下。定义依然利用PHP_FUNCTION实现,括号内是定义的函数名。这里声明了该函数的两个 long int 类型变量,还有一个字符串 char *c, 要注意的一点便是,当声明字符串类型变量时,我们需要为其声明长度,即下面的int c_len。条件语句 if 中的参数  "lls" 对应三个变量,分别是 long, long 和 char *,函数的最后将输出结果存到 char *str 变量中,而 RETURN_STRINGL 表示返回的是该字符串,STRINGL中的L表示指定返回字符串的长度。 PHP扩展还提供了其他许多的返回类型,包括对象之类的,这里便不列出, 这些东西都存在于php源码中子文件夹zend的 zeng_API.h 文件中。 

<span style="font-size:14px;">PHP_FUNCTION(hello_world)
{
     long a;
     long b;
     char *c;
     int c_len;
 
     // <span style="font-family: Arial, Helvetica, sans-serif;">zend_parse_parameters 是 </span><span style="font-family: Arial, Helvetica, sans-serif;">PHP 其中的一个API, 用于从PHP中获取对应的参数</span>
     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lls", &a, &b, &c, &c_len) == FAILURE){
         return ;
     }
     char *str;
     int len = spprintf(&str, 0, "%s: %d\n", c, a*b);
 
     RETURN_STRINGL(str, len, 0); // PHP提供的返回类型
}</span>


完成上述文件的声明和定义之后,我们还需要继续在 test.c 文件中找到以下语句,并将 PHP_FE 中的参数换为刚刚的函数名 hello_world 和 NULL,不然PHP会提示没法找到hello_world函数。保存之后我们直接利用sudo make install 重新编译当前的 C 源码,然后就可以写个 php脚本测试该函数是否可用了。

<span style="font-size:14px;">const zend_function_entry test_functions[] = {
    PHP_FE(hello_world,    NULL)       /* For testing, remove later. */
    PHP_FE_END  /* Must be the last line in test_functions[] */
};</span>


首先我们先利用 php --rf "hello_world" 查看该函数是否存在,在 test 文件夹中输入该命令后出现类似如下的结果,表示对应的函数存在:(这里我查看的是echo_hello_world函数)


写个小php脚本测试,脚本简单如下所示:

<span style="font-size:14px;"><?php
echo hello_world(100, 345, "hello world:100*345=");</span>

保存成test3.php 退出后利用 php test3.php执行, 即可看到结果,如下所示:



你可能感兴趣的:(c,linux,mac,PHP扩展,函数扩展)