PHP扩展开发

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

你可能感兴趣的:(PHP扩展开发)