给PHP7.4编写扩展
本文是以 PHP7.4
作为基础,讲解如何从零开始创建一个 PHP
扩展。本文主要讲解创建一个扩展的基本步骤都有哪些。示例中,我们将实现如下功能:
<?php echo hello();
输出内容:
// $ php74 ./hello.php $ hello word
在扩展中实现一个 hello
方法,调用 hello
方法后,输出 hello word!
。
生成扩展骨架
首先我们要有一份 php-src
git clone https://github.com/php/php-src.git cd php-src git checkout PHP-7.4.5 cd php-7.4.10/ext ls
可以看到有一个 ext_skel.php
文件
bcmath com_dotnet date enchant ffi ftp gmp imap ldap mysqli odbc pcntl pdo_dblib pdo_oci pdo_sqlite posix reflection simplexml soap spl sysvmsg tidy xmlreader xsl zlib bz2 ctype dba exif fileinfo gd hash intl libxml mysqlnd opcache pcre pdo_firebird pdo_odbc pgsql pspell session skeleton sockets sqlite3 sysvsem tokenizer xmlrpc zend_test calendar curl dom ext_skel.php filter gettext iconv json mbstring oci8 openssl pdo pdo_mysql pdo_pgsql phar readline shmop snmp sodium standard sysvshm xml xmlwriter zip
这个已经文件已经跟 php
一起发布了,所以我们自定义起来非常方便
php ext_skel.php --ext hello --author aoppp --std 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/hello phpize ./configure make Don't forget to run tests once the compilation is done: make test Thank you for using PHP!
在 ext
目录下便生成 hello
目录
扩展骨架说明
-rw-r--r-- 1 longshilin staff 405 Feb 27 16:07 .gitignore -rw-r--r-- 1 longshilin staff 11 Feb 27 16:07 CREDITS -rw-r--r-- 1 longshilin staff 3231 Feb 27 16:07 config.m4 -rw-r--r-- 1 longshilin staff 204 Feb 27 16:07 config.w32 -rw-r--r-- 1 longshilin staff 3355 Feb 27 16:07 hello.c -rw-r--r-- 1 longshilin staff 1425 Feb 27 16:07 php_hello.h drwxr-xr-x 5 longshilin staff 160 Feb 27 16:07 tests
- config.m4配置文件
扩展的 config.m4
文件告诉 UNIX
构建系统哪些扩展 configure
选项是支持的,你需要哪些扩展库,以及哪些源文件要编译成它的一部分。对所有经常使用的 autoconf
宏,包括 PHP
特定的及 autoconf
内建的。
config.m4
的作用就是配合 phpize
工具生成 configure
文件。configure
文件是用于环境检测的。检测扩展编译运行所需的环境是否满足。现在我们开始修改 config.m4
文件。
其中,dnl
是注释符号。
上面的代码说,如果你所编写的扩展如果依赖其它的扩展或者 lib
库,需要去掉 PHP_ARG_WITH
相关代码的注释。否则,去掉 PHP_ARG_ENABLE
相关代码段的注释。我们编写的扩展不需要依赖其他的扩展和 lib
库。因此,我们去掉 PHP_ARG_ENABLE
前面的注释。
上图生成的时候就已经指定是不依赖其他的扩展。
- php_hello.h 头文件
类似于C语言的头文件,包含了一些自定义的结构和函数声明,在这个demo
中暂时不需要改动 - hello.c代码文件
真正的逻辑代码都在这个文件中
编写代码
hello.c 里面都是逻辑代码,所以我们增加代码在这个文件中操作即可
了解扩展入口
整个扩展的入口是 zend_module_entry
这个结构,具体的定义可以在 Zend
目录下的zend_modules.h
文件中看到,一共有十几个属性,快速跳过,我们暂时只需要 hello
zend_module_entry hello_module_entry = { STANDARD_MODULE_HEADER, "hello", /* Extension name */ hello_functions, /* zend_function_entry */ NULL, /* PHP_MINIT - Module initialization */ NULL, /* PHP_MSHUTDOWN - Module shutdown */ PHP_RINIT(hello), /* PHP_RINIT - Request initialization */ NULL, /* PHP_RSHUTDOWN - Request shutdown */ PHP_MINFO(hello), /* PHP_MINFO - Module info */ PHP_HELLO_VERSION, /* Version */ STANDARD_MODULE_PROPERTIES };
扩展相关属性说明:
- STANDARD_MODULE_HEADER 帮我们实现了前面6个属性
- hello 是扩展名称
- hello_functions 是扩展包含的全部方法的集合,后面5个宏分别代表5个扩展特定方法
- PHP_HELLO_VERSION 是扩展的版本号,定义在头文件中,如果需要修改的话直接打开
php_hello.h
找到define PHP_LZPAY_VERSION
进行修改 - STANDARD_MODULE_PROPERTIES 帮我们实现了剩下的属性
在 hello_functions[]
方法数组中已经有了2个示例方法hello_test1
和hello_test2
,我们参考它写我们的方法,首先我们写一个测试方法,放到函数 PHP_FUNCTION(hello_test2)
后面:
/*新增函数*/ PHP_FUNCTION(hello) { zend_string *strg; strg = strpprintf(0, "hello word"); RETURN_STR(strg); }
然后在 hello_functions[]
数组中增加我们新写的函数
编译安装
因为我是新安装的一个独立的 php7.4
,所以我的操作基本上都是带绝对路径的,如果大家就一个环境直接操作就行
cd hello/ /usr/local/Cellar/php/7.4.0/bin/phpize ./configure --with-php-config=/usr/local/Cellar/php/7.4.0/bin/php-config make && make install ---------------------------------------------------------------------------- Build complete. Don't forget to run 'make test'. Installing shared extensions: /usr/local/Cellar/php/7.4.0/pecl/20190902/
安装好了,我们配置一下这个扩展
- ext-hello.ini
[hello] extension="/usr/local/Cellar/php/7.4.0/pecl/20190902/hello.so"
测试
hello git:(PHP-7.4.5) $ /usr/local/Cellar/php/7.4.0/bin/php -m | grep hello # 输出成功说明ok hello