5.1 Your First Extension

配置文件

才开始,我们先用最快的(不是最标准的)的方式来建立一个代码最少的扩展。在php源码文件夹的ext目录下创建一个新的文件夹,这里我取的名字叫做walu,它往往就是我们扩展的名字。其实这个文件夹可以放在任何一个位置,但是为了我们在后面介绍win32的编译与静态编译,我们还是把它放在php源码的ext目录下。现在,我们在这个目录下创建一个config.m4文件,并输入以下内容:

  1. PHP_ARG_ENABLE(walu,
  2. [Whether to enable the "walu" extension],
  3. [ enable-walu Enable "walu" extension support])
  4. if test $PHP_WALU != "no"; then
  5. PHP_SUBST(WALU_SHARED_LIBADD)
  6. PHP_NEW_EXTENSION(walu, walu.c, $ext_shared)
  7. fi

上面PHP_ARG_ENABLE函数有三个参数,第一个参数是我们的扩展名(注意不用加引号),第二个参数是当我们运行./configure脚本时显示的内容,最后一个参数则是我们在调用./configure —help时显示的帮助信息。

也许有人会问,为什么有的扩展的开启方式是 —enable-extname的形式,有的则是—with-extname的形式呢?其实两者并没有什么本质的不同,只不过enable多代表不依赖外部库便可以直接编译,而with大多需要依赖于第三方的lib。现在,我们的扩展并不需要依赖其它的库文件,所以我们直接使用—enable-walu便可以了。在第17章的时候我们将接触通过CFLAGS和LDFLAGS来配置自己的扩展,使其依赖第三方库文件才能被编译成php扩展。

如果我们显示运行./configure —enable-walu,那么终端环境便会自动将$PHP_WALU变量设置为yes,而PHP_SUBST函数只不过是php官方对autoconf里的AC_SUBST函数的一层封装。最后重要的一点是,PHP_NEW_EXTENSION函数声明了这个扩展的名称、需要的源文件名、此扩展的编译形式。如果我们的扩展使用了多个文件,便可以将这多个文件名罗列在函数的参数里,如:

  1. PHP_NEW_EXTENSION(sample, sample.c sample2.c sample3.c, $ext_shared)

最后的$ext_shared参数用来声明这个扩展不是一个静态模块,而是在php运行时动态加载的。

下面,我们来编写实现扩展主逻辑的源文件walu.c:

  1. //加载config.h,如果配置了的话
  2. #ifdef HAVE_CONFIG_H
  3. #include "config.h"
  4. #endif
  5. //加载php头文件
  6. #include "php.h"
  7. #define phpext_walu_ptr &walu_module_entry
  8. //module entry
  9. zend_module_entry walu_module_entry = {
  10. #if ZEND_MODULE_API_NO >= 20010901
  11. STANDARD_MODULE_HEADER,
  12. #endif
  13. "walu", //这个地方是扩展名称,往往我们会在这个地方使用一个宏。
  14. NULL, /* Functions */
  15. NULL, /* MINIT */
  16. NULL, /* MSHUTDOWN */
  17. NULL, /* RINIT */
  18. NULL, /* RSHUTDOWN */
  19. NULL, /* MINFO */
  20. #if ZEND_MODULE_API_NO >= 20010901
  21. "2.1", //这个地方是我们扩展的版本
  22. #endif
  23. STANDARD_MODULE_PROPERTIES
  24. };
  25. #ifdef COMPILE_DL_WALU
  26. ZEND_GET_MODULE(walu)
  27. #endif

这就是所有的代码了,不过鉴于我们平时的开发习惯,往往会把这一份代码分成两份,一个.h文件,一个.c文件。上面的代码只是生成了一基本的框架,而没有任何实际的用处。紧接着,创建一个zend_module_entry结构体,你肯定已经发现了,依据ZEND_MODULE_API_NO 是否大于等于 20010901,这个结构体需要不同的定义格式。20010901大约代表PHP4.2.0版本,所以我们现在的扩展几乎都要包含STANDARD_MODULE_HEADER这个元素了。其余六个成员我们可以先赋值为NULL,其实看看它们各自后面的注释你就应该大体上了解它们各自是负责哪一方面的工作了。最后,最底下的代码用来标志我们的这个扩展是一个shared module。它是干么的呢?我也说不清楚,反正带上就对了,否则扩展会工作不正常。原文解释:This brief conditional simply adds a reference used by Zend when your extension is loaded dynamically. Don’t worry about what it does or how it does it too much; just make sure that it’s around or the next section won’t work.

标准一些

根据我们平时的开发习惯,应该不会把所有代码都写在这一个文件里的,我们需要把上述代码放在两个文件里,一个头文件,一个c文件。

  1. //php_walu.h
  2. #ifndef WALU_H
  3. #define WALU_H
  4. //加载config.h,如果配置了的话
  5. #ifdef HAVE_CONFIG_H
  6. #include "config.h"
  7. #endif
  8. //加载php头文件
  9. #include "php.h"
  10. #define phpext_walu_ptr &walu_module_entry
  11. extern zend_module_entry walu_module_entry;
  12. #endif

下面的是c文件

  1. //walu.c
  2. #include "php_walu.h"
  3. //module entry
  4. zend_module_entry walu_module_entry = {
  5. #if ZEND_MODULE_API_NO >= 20010901
  6. STANDARD_MODULE_HEADER,
  7. #endif
  8. "walu", //这个地方是扩展名称,往往我们会在这个地方使用一个宏。
  9. NULL, /* Functions */
  10. NULL, /* MINIT */
  11. NULL, /* MSHUTDOWN */
  12. NULL, /* RINIT */
  13. NULL, /* RSHUTDOWN */
  14. NULL, /* MINFO */
  15. #if ZEND_MODULE_API_NO >= 20010901
  16. "2.1", //这个地方是我们扩展的版本
  17. #endif
  18. STANDARD_MODULE_PROPERTIES
  19. };
  20. #ifdef COMPILE_DL_WALU
  21. ZEND_GET_MODULE(walu)
  22. #endif