Linux下PHP7扩展开发入门教程1:扩展开发流程

本文将会基于PHP7开发一个最简单的扩展,随便取个名learn_ext,编译生成一个learn_ext.so文件,最终调用可以在php中调用learn_ext扩展中的函数来输出一个hello world,并且可以在phpinfo()中看到learn_ext展信息。

开始之前

  1. 你需要有PHP和C语言/C++基础
  2. 掌握Linux下编译安装PHP
  3. 本次使用PHP7.4进行扩展开发
  4. 在Linux上安装PHP7.4环境
  5. 根据你的个人习惯,使用Centos、Ubuntu或其它系统均可。

参考资料:

下载PHP源码包

下载源码包:

1
wget https://www.php.net/distributions/php-7.4.4.tar.gz

如果下载速度太慢,可以使用国内的地址:

1
wget https://share-disk-1252104623.cos.ap-guangzhou.myqcloud.com/php-7.4.4.tar.gz

下载完成后,解压源代码,进入源代码的扩展目录:

1
2
tar zxvf php-7.4.4.tar.gz 
cd php-7.4.4/ext

生成扩展开发的基本骨架

在扩展目录(ext)中,有一个ext_skel.php脚本,可以用于生成扩展开发的基本骨架。这个脚本是用PHP编写的,因此你需要提前安装好PHP环境。

执行脚本php ext_skel.php --help可以看到说明和常用参数。对于初学者来说,只需要了解--ext这个参数就够了。

创建一个叫做learn_ext的扩展:

1
php ext_skel.php --ext learn_ext

顺利的话,会看到扩展开发的一些提示:

Copying config scripts… done
Copying sources… done
Copying tests… done

Success. The extension is now ready to be compiled. To do so, use the
following steps:

cd /path/to/php-src/learn_ext
phpize
./configure
make

Don’t forget to run tests once the compilation is done:
make test

Thank you for using PHP!

这个操作会在ext/目录下生成一个learn_ext目录,查看learn_ext目录中的文件如下:

1
2
3
4
5
config.m4  
config.w32
learn_ext.c
php_learn_ext.h
tests

我们主要关注的文件是learn_ext.c,这是扩展的源代码文件。在这个文件中,已经有两个函数的例子写在learn_ext.c里面了。
第一个函数:

1
2
3
4
5
6
7
8
9
/* {{{ 
*/
PHP_FUNCTION(learn_ext_test1)
{
ZEND_PARSE_PARAMETERS_NONE();

php_printf("The extension %s is loaded and working!\r\n", "learn_ext");
}
/* }}} */

从注释中可以看出这个,函数原型是void learn_ext_test1(),一个没有参数也没有返回值的函数learn_ext_test1,函数运行后将会打印一句话:The extension learn_ext is loaded and working!

第二个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* {{{ string learn_ext_test2( [ string $var ] )
*/
PHP_FUNCTION(learn_ext_test2)
{
char *var = "World";
size_t var_len = sizeof("World") - 1;
zend_string *retval;

ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(var, var_len)
ZEND_PARSE_PARAMETERS_END();

retval = strpprintf(0, "Hello %s", var);

RETURN_STR(retval);
}

同样,注释中标注了函数原型是string learn_ext_test2( [ string $var ] ),即参数是一个字符串类型的可选参数,返回值也是一个字符串。
从源代码可以看出来,这个函数会返回Hello %s,其中%s是参数varvar参数是可选的,如果没有传入参数,则使用默认值char *var = "World";,最后返回字符串Hello World

编译扩展

根据上面创建扩展骨架时的提示:

The extension is now ready to be compiled. To do so, use the
following steps:

cd /path/to/php-src/learn_ext
phpize
./configure
make

按照提示中的流程,进入到learn_ext扩展目录,使用phpize命令编译扩展:

1
2
3
4
5
root@ed78d89e5328:~/php-7.4.4/ext/learn_ext# phpize
Configuring for:
PHP Api Version: 20190902
Zend Module Api No: 20190902
Zend Extension Api No: 320190902

检查并生成编译配置:

1
./configure

编译扩展:

1
make

很快,编译完成。顺利的话,在learn_ext扩展目录下的modules目录,会生成一个learn_ext.so,这个就是最终生成的扩展二进制文件。

安装扩展

编辑PHP配置文件php.ini,增加一行扩展配置:

1
extension=/root/php-7.4.4/ext/learn_ext/modules/learn_ext.so

测试扩展是否生效

以下几种方法都可以验证扩展是否安装成功:

  1. 不用重启PHP,使用php -m命令打印已安装的扩展,可以找到learn_ext说明扩展安装成功。

    1
    2
    root@ed78d89e5328:~# php -m |grep learn_ext
    learn_ext
  2. 创建一个PHP脚本test.php,可以调用扩展里面的方法:

    1
    2
    3
    4
    5
    6
    7
    <?php
    learn_ext_test1();
    echo "\n";
    echo learn_ext_test2();
    echo "\n";
    echo learn_ext_test2("learn_ext");
    echo "\n";

    保存后,执行php test.php, 输出:

    The extension learn_ext is loaded and working!

    Hello World
    Hello learn_ext

  3. 查看phpinfo():

    1
    2
    3
    root@ed78d89e5328:~# php -r "phpinfo();"|grep learn_ext
    learn_ext
    learn_ext support => enabled

    如果是在网页中查看phpinfo, 需要重启php-fpm或nginx/apache。

下一步

以上就是扩展开发和安装的流程。

接下来,了解函数的组成部分:
Linux下PHP7扩展开发入门教程2: 函数结构详解