1、生成描述文件,包含对函数等的定义
[chengyi@localhost php-extension]$ cat hello_cy.def
string self_concat(string str, int n);
2、进入PHP源码的ext目录
[chengyi@localhost ext]$ pwd
/home/chengyi/centos_soft_install/php-5.2.5/ext
3、查看ext_skel的帮助,我们主要用到的是 --extname=module 定义将要生成的模块名称; --proto=file 指向刚才的描述函数定义的文件。
[chengyi@localhost ext]$ ./ext_skel --help
./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-cvs
--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
4、执行ext_skel,生成空模块
[chengyi@localhost ext]$ ./ext_skel --extname=hello_cy --proto=/home/chengyi/test-all/php-extension/hello_cy.def
Creating directory hello_cy
awk: /home/chengyi/centos_soft_install/php-5.2.5/ext/skeleton/create_stubs:56: warning: escape sequence `/|' treated as plain `|'
Creating basic files: config.m4 config.w32 .cvsignore hello_cy.c php_hello_cy.h CREDITS EXPERIMENTAL tests/001.phpt hello_cy.php [done].
To use your new extension, you will have to execute the following steps:
1. $ cd ..
2. $ vi ext/hello_cy/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-hello_cy
5. $ make
6. $ ./php -f ext/hello_cy/hello_cy.php
7. $ vi ext/hello_cy/hello_cy.c
8. $ make
Repeat steps 3-6 until you are satisfied with ext/hello_cy/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.
5、将生成的空模块mv到自己的目录下去(这里我们没有按照上面ext_skel的说明来做)
[chengyi@localhost ext]$ mv hello_cy/ ~/test-all/php-extension/
6、进入到空模块下,查看都生成了哪些文件
[chengyi@localhost hello_cy]$ ls -p
config.m4 config.w32 CREDITS EXPERIMENTAL hello_cy.c hello_cy.php php_hello_cy.h tests/
可以看到,有一个tests目录。
7、修改config.m4文件,打开编译选项
PHP_ARG_ENABLE(hello_cy, whether to enable hello_cy support,
[ --enable-hello_cy Enable hello_cy support])
if test "$PHP_HELLO_CY" != "no"; then
AC_DEFINE(HAVE_HELLO_CY, 1, [Whether you have Hello World])
PHP_NEW_EXTENSION(hello_cy, hello_cy.c, $ext_shared)
fi
8、执行phpize生成更多文件,为编译做准备
[chengyi@localhost hello_cy]$ phpize
Configuring for:
PHP Api Version: 20041225
Zend Module Api No: 20060613
Zend Extension Api No: 220060519
[chengyi@localhost hello_cy]$ ls
acinclude.m4 build config.m4 configure.in EXPERIMENTAL install-sh missing run-tests.php
aclocal.m4 config.guess config.sub config.w32 hello_cy.c ltmain.sh mkinstalldirs tests
autom4te.cache config.h.in configure CREDITS hello_cy.php Makefile.global php_hello_cy.h
9、开始编译
./configure --enable-hello_cy
make
make test
sudo make install (有时php ext路径不对,就手工cp过去)
10、测试
[chengyi@localhost hello_cy]$ php hello_cy.php
Functions available in the test extension:
confirm_hello_cy_compiled
self_concat
Congratulations! You have successfully modified ext/hello_cy/config.m4. Module hello_cy is now compiled into PHP.
11、如果想要重新获取到一个干净的目录,执行 phpize --clean
12、将扩展加载,修改php.ini文件
如果不确定php.ini的位置,执行如下:
[chengyi@localhost hello_cy]$ php -i|grep "php.ini"
Configuration File (php.ini) Path => /usr/local/php/lib
Loaded Configuration File => /usr/local/php/lib/php.ini
可以看到,该文件在/usr/local/php/lib/php.ini。
在该文件中添加: extension=hello_cy.so
然后重启apache,如果需要在web端执行的话(如果仅在本地脚本执行,则不用重启apache,因为压根没关系)。
-----------------------------------------------------
探求代码为什么这么写呢?
首先要声明,探求这些只能去PHP的源码看了。源码中比较重要的两个目录是main和Zend。
1、PHP_FUNCTION(self_concat){} 是个什么东西?为什么要用它来定义我们的函数呢?
我们在里面找寻PHP_FUNCTION的定义,在main/下:
php.h:#define PHP_FUNCTION ZEND_FUNCTION
然后我们去Zend/目录下,发现了 ZEND_FUNCTION的定义:
zend_API.h:#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
然后继续由 ZEND_NAMED_FUNCTION, ZEND_FN的定义追查下去得到: void zif_name(INTERNAL_FUNCTION_PARAMETERS)
再看INTERNAL_FUNCTION_PARAMETERS (其实php源码下都有tags,直接ctrl+]就可以跟踪定义了),得到完整的函数定义:
void zif_name(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC); // 其实我还蛮好奇这几个参数为什么要这样设置的,等有空去仔细看源码
2、怎样返回值?
我们经常使用的返回值的宏是 RETURN_STRING之类的,去Zend/下找它的定义:
#define RETURN_STRING(s, duplicate) { RETVAL_STRING(s, duplicate); return; }
#define RETVAL_STRING(s, duplicate) ZVAL_STRING(return_value, s, duplicate)
可以看出,是给函数定义的参数return_value赋值了,然后估计是由PHP内部的机制,直接把return_value返回。