PHP程序员大概都知道可以用C/C++来扩展PHP。现在网络上关于PHP扩展开发的资料也已经很多了,假如你恰巧有C/C++基础,那么不妨进阶学习开发PHP扩展。下面以一个简单示例 tl_toolkit 来介绍PHP扩展开发流程。
开发环境
1. CentOS 7.5
2. PHP 7.1 源码
开发步骤
1. 生成扩展目录
PHP源码扩展目录ext/中包含生成扩展基本目录的工具ext_skel
,使用该工具可以很方便的生成扩展基本目录。
[root@ef40a04d7af1 ext]# ./ext_skel
./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]]
[--skel=dir] [--full-xml] [--no-help]
--extname=module module is the name of your extension
--proto=file file contains prototypes of functions to create
--stubs=file generate only function stubs in file
--xml generate xml documentation to be added to phpdoc-svn
--skel=dir path to the skeleton directory
--full-xml generate xml documentation for a self-contained extension
(not yet implemented)
--no-help don't try to be nice and create comments in the code
and helper functions to test if the module compiled
生成扩展基本目录很简单,如下:
[root@ef40a04d7af1 ext]# ./ext_skel --extname=tl_toolkit
Creating directory tl_toolkit
Creating basic files: config.m4 config.w32 .gitignore tl_toolkit.c php_tl_toolkit.h CREDITS EXPERIMENTAL tests/001.phpt tl_toolkit.php [done].
To use your new extension, you will have to execute the following steps:
1. $ cd ..
2. $ vi ext/tl_toolkit/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-tl_toolkit
5. $ make
6. $ ./sapi/cli/php -f ext/tl_toolkit/tl_toolkit.php
7. $ vi ext/tl_toolkit/tl_toolkit.c
8. $ make
Repeat steps 3-6 until you are satisfied with ext/tl_toolkit/config.m4 and
step 6 confirms that your module is compiled into PHP. Then, start writing
code and repeat the last two steps as often as necessary.
2. 实现扩展方法
2.1 修改config.m4
文件。config.m4
文件内说明,该文件以dnl
为注释符。
1 dnl $Id$
2 dnl config.m4 for extension tl_toolkit
3
4 dnl Comments in this file start with the string 'dnl'.
5 dnl Remove where necessary. This file will not work
6 dnl without editing.
7
8 dnl If your extension references something external, use with:
9
10 dnl PHP_ARG_WITH(tl_toolkit, for tl_toolkit support,
11 dnl Make sure that the comment is aligned:
12 dnl [ --with-tl_toolkit Include tl_toolkit support])
13
14 dnl Otherwise use enable:
15
16 PHP_ARG_ENABLE(tl_toolkit, whether to enable tl_toolkit support,
17 Make sure that the comment is aligned:
18 [ --enable-tl_toolkit Enable tl_toolkit support])
删除config.m4
文件中16至18行前dnl
。
2.2 引用多个.c源文件(可选)。如果你的扩展,包含多个c源文件,那么在config.m4
文件最后PHP_NEW_ EXTENSION函数内引用进来。tl_toolkit扩展就增加一个tl_string.c
文件。那么就像如下引用进来:
PHP_NEW_EXTENSION(tl_toolkit, tl_toolkit.c tl_string.c, $ext_shared, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
2.3 修改php_tl_toolkit.h
头文件,在最后#endif /* PHP_TEST_H */
前添加PHP_FUNCTION(tl_get_arch);
2.4 实现tl_get_arch方法。这个方法的作用是获取系统位数,返回32或者64。具体实现我们使用phalcon项目中的代码。所以在tl_string.c
中tl_get_arch的实现就是:
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
/*{{ tl_get_arch
*/
PHP_FUNCTION(tl_get_arch)
{
#ifndef ENVIRONMENT32
RETURN_LONG(64);
#else
RETURN_LONG(32);
#endif
}
/* }}} */
2.5 注册tl_get_arch方法。在ext_skel
生成的扩展源码文件tl_toolkit.c
中,找到zend_function_entry添加PHP_FE(tl_get_arch, NULL)。
116 /* {{{ tl_toolkit_functions[]
117 *
118 * Every user visible function must have an entry in tl_toolkit_functions[].
119 */
120 const zend_function_entry tl_toolkit_functions[] = {
121 PHP_FE(tl_toolkit_info, NULL)
122 PHP_FE(tl_authcode, NULL)
123 PHP_FE(tl_get_arch, NULL)
124 PHP_FE_END
125 };
126 /* }}} */
3. 添加测试用例
ext_skel
生成的扩展目录包含一个tests目录,里面有一个001.phpt
测试文件。编译扩展时执行make test
就会运行这些测试用例文件。*.phpt
的结构说明如下:
--TEST-- : 测试用例名
--SKIPIF-- : 跳过测试用例的条件
--INI--: 执行测试用例需要的ini配置
--FILE-- : 测试用例运行的php代码
--EXPECT-- : 期望输出结果
所以我为tl_get_arch方法添加一个测试用例如003.phpt
下:
1 --TEST--
2 Test function tl_get_arch of tl_toolkit
3
4 --SKIPIF--
5
6
7 --FILE--
8
11
12 --EXPECT--
13 64
4. 编译安装扩展
在扩展目录执行:
/usr/local/php/bin/phpize
./configure
make && make install
make成功后会提示执行make test,执行make test会输出如下结构信息:
=====================================================================
PHP : /usr/local/php-7.1.12/bin/php
---------------------------------------------------------------------
PHP : /usr/local/php-7.1.12/bin/phpdbg
---------------------------------------------------------------------
CWD : /root/Download/php-7.1.12/ext/tl_toolkit
Extra dirs :
VALGRIND : Not used
=====================================================================
TIME START 2019-03-12 22:33:19
=====================================================================
PASS Check for tl_toolkit presence [tests/001.phpt]
PASS Test function tl_authcode of tl_toolkit [tests/002.phpt]
PASS Test function tl_get_arch of tl_toolkit [tests/003.phpt]
=====================================================================
TIME END 2019-03-12 22:33:19
=====================================================================
TEST RESULT SUMMARY
---------------------------------------------------------------------
Exts skipped : 0
Exts tested : 1
---------------------------------------------------------------------
Number of tests : 3 3
Tests skipped : 0 ( 0.0%) --------
Tests warned : 0 ( 0.0%) ( 0.0%)
Tests failed : 0 ( 0.0%) ( 0.0%)
Expected fail : 0 ( 0.0%) ( 0.0%)
Tests passed : 3 (100.0%) (100.0%)
---------------------------------------------------------------------
Time taken : 0 seconds
=====================================================================
最后,修改php.ini文件,添加extension=tl_toolkit.so
,并重启php,然后就可以在php代码中调用tl_get_arch
方法了。
tl_toolkit扩展完整的代码移步GitHub
相关资料
下面是我在学习PHP扩展开发时收集的一些资料,都是PHP界大牛写的博客或书籍,整理分享出来方便学习,希望能帮助想学PHP扩展或者正在学习的人。
1. 《深入理解PHP内核》
2. 《PHP扩展开发及内核应用》
3. 信海龙PHP7扩展系列博文
4. PHP Internals Book