首页 >后端开发 >php教程 >如何编写一个php扩展

如何编写一个php扩展

伊谢尔伦
伊谢尔伦原创
2017-06-27 09:16:472747浏览

每一个php扩展的构建至少需要两个文件: 一个configuration文件, 它告诉编译期要构建哪些文件以及需要什么外部的库, 还需要至少一个源文件, 它执行实际的工作.

剖析扩展

实际上, 通常会有第二个或第三个配置文件, 以及一个或多个头文件. 对于你的第一个扩展, 你需要添加每种类型的一个文件并使用它们工作.

配置文件

要开始了, 首先在你的php源代码目录树的ext/目录下创建名为sample的目录. 实际上这个新的目录可以放在任何地方, 但是为了在本章后面演示win32和静态构建选项, 我们还是先建立在源代码目录下吧.

下一步, 进入这个目录, 创建一个名为config.m4的文件, 键入下面内容:

PHP_ARG_ENABLE(sample,  
  [Whether to enable the "sample" extension],  
  [  enable-sample        Enable "sample" extension support])  
      
if test $PHP_SAMPLE != "no"; then  
  PHP_SUBST(SAMPLE_SHARED_LIBADD)  
  PHP_NEW_EXTENSION(sample, sample.c, $ext_shared)  
fi

这是./configure时能够调用enable-sample选项的最低要求.PHP_ARG_ENABLE的第二个参数将在./configure处理过程中到达这个扩展的配置文件时显示. 第三个参数将在终端用户执行./configure --help时显示为帮助信息.

有没有想过为什么有的扩展配置使用enable-extname, 而有的扩展则使用with-extname? 功能上两者没有区别. 实际上, enable表示启用这个特性不需要其他任何第三方库, 相比之下, with则表示要使用这个特性还有其他先决条件

现在, 你的sample扩展并不需要和其他库链接, 因此只需要使用enable版本. 在第17章"外部库"中, 我们将介绍使用with并指示编译器使用额外的CFLAGS和LDFLAGS设置.

如果终端用户使用enable-sample选项调用了./configure, 那么本地的环境变量$PHP_SAMPLE, 将被设置为yes. PHP_SUBST()是标准autoconf的AC_SUBST()宏的php修改版, 它在将扩展构建为共享模块时需要.

最后但并不是不重要的, PHP_NEW_EXTENSION()定义了模块并枚举了所有必须作为扩展的一部分编译的源文件. 如果需要多个文件, 它可以在第二个参数中使用空格分隔列举, 例如:

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

最后一个参数是对应于PHP_SUBST(SAMPLE_SHARED_LIBADD)命令的, 在构建共享模块的时候同样需要它.

头文件

当使用C开发的时候, 将数据的类型定义放到外部的头文件中隔离起来, 由源文件包含是常见的做法. 尽管php并不要求这样, 但是这样做在模块增长到不能放到单个源文件时是有简化作用的.

在你的php_sample.h头文件中, 以下面内容开始:

#ifndef PHP_SAMPLE_H  
/* 防止重复包含 */
#define PHP_SAMPLE_H  
      
/* 定义扩展的属性 */
#define PHP_SAMPLE_EXTNAME    "sample"  
#define PHP_SAMPLE_EXTVER    "1.0"  
      
/* 在php源码树外面构建时引入配置选项 */
#ifdef HAVE_CONFIG_H  
#include "config.h"  
#endif  
      
/* 包含php的标准头文件 */
#include "php.h"  
      
/* 定义入口点符号, Zend在加载这个模块的时候使用 */
extern zend_module_entry sample_module_entry;  
#define phpext_sample_ptr &sample_module_entry  
      
#endif /* PHP_SAMPLE_H */

这个头文件完成了两个主要的任务: 如果扩展使用phpize工具构建(本书通常都使用这种方式), 那么HAVE_CONFG_H就是已定义的, 这样config.h就会被正常的包含进来. 无论扩展怎样编译, 都会从php源码树中包含php.h. 这个头文件中包含了php源码中访问大部分PHPAPI要使用的其他头文件.

接下来, 你的扩展使用的zend_module_entry结构定义为外部的, 这样当这个模块使用extension=xxx加载时, 就可以被Zend使用dlopen和dlsym()取到.

头文件中还会包含一些预处理, 定义将在原文件中使用的信息.

源代码

最后, 最重要的你需要在sample.c中创建一个简单的源码骨架:

#include "php_sample.h"  
      
zend_module_entry sample_module_entry = {  
#if ZEND_MODULE_API_NO >= 20010901  
     STANDARD_MODULE_HEADER,  
#endif  
    PHP_SAMPLE_EXTNAME,  
    NULL, /* Functions */
    NULL, /* MINIT */
    NULL, /* MSHUTDOWN */
    NULL, /* RINIT */
    NULL, /* RSHUTDOWN */
    NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901  
    PHP_SAMPLE_EXTVER,  
#endif  
    STANDARD_MODULE_PROPERTIES  
};  
      
#ifdef COMPILE_DL_SAMPLE  
ZEND_GET_MODULE(sample)  
#endif

以上是如何编写一个php扩展的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn