# 5.1 Your First Extension
### 配置文件
才开始,我们先用最快的(不是最标准的)的方式来建立一个代码最少的扩展。在php源码文件夹的ext目录下创建一个新的文件夹,这里我取的名字叫做walu,它往往就是我们扩展的名字。其实这个文件夹可以放在任何一个位置,但是为了我们在后面介绍win32的编译与静态编译,我们还是把它放在php源码的ext目录下。
现在,我们在这个目录下创建一个config.m4文件,并输入以下内容:
PHP_ARG_ENABLE(walu,
[Whether to enable the "walu" extension],
[ enable-walu Enable "walu" extension support])
if test $PHP_WALU != "no"; then
PHP_SUBST(WALU_SHARED_LIBADD)
PHP_NEW_EXTENSION(walu, walu.c, $ext_shared)
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函数声明了这个扩展的名称、需要的源文件名、此扩展的编译形式。如果我们的扩展使用了多个文件,便可以将这多个文件名罗列在函数的参数里,如:
PHP_NEW_EXTENSION(sample, sample.c sample2.c sample3.c, $ext_shared)
最后的$ext_shared参数用来声明这个扩展不是一个静态模块,而是在php运行时动态加载的。
下面,我们来编写实现扩展主逻辑的源文件walu.c:
````c
//加载config.h,如果配置了的话
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
//加载php头文件
#include "php.h"
#define phpext_walu_ptr &walu_module_entry
//module entry
zend_module_entry walu_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"walu", //这个地方是扩展名称,往往我们会在这个地方使用一个宏。
NULL, /* Functions */
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
"2.1", //这个地方是我们扩展的版本
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_WALU
ZEND_GET_MODULE(walu)
#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文件。
````c
//php_walu.h
#ifndef WALU_H
#define WALU_H
//加载config.h,如果配置了的话
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
//加载php头文件
#include "php.h"
#define phpext_walu_ptr &walu_module_entry
extern zend_module_entry walu_module_entry;
#endif
````
下面的是c文件
````c
//walu.c
#include "php_walu.h"
//module entry
zend_module_entry walu_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"walu", //这个地方是扩展名称,往往我们会在这个地方使用一个宏。
NULL, /* Functions */
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
"2.1", //这个地方是我们扩展的版本
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_WALU
ZEND_GET_MODULE(walu)
#endif
````
## links
* 5 [Your First Extension](<5.md>)
* 5.2 [编译我们的扩展](<5.2.md>)
- about
- 开始阅读
- 目录
- 1 PHP的生命周期
- 1.让我们从SAPI开始
- 2.PHP的启动与终止
- 3.PHP的生命周期
- 4.线程安全
- 5.小结
- 2 PHP变量在内核中的实现
- 1. 变量的类型
- 2. 变量的值
- 3. 创建PHP变量
- 4. 变量的存储方式
- 5. 变量的检索
- 6. 类型转换
- 7. 小结
- 3 内存管理
- 1. 内存管理
- 2. 引用计数
- 3. 总结
- 4 动手编译PHP
- 1. 编译前的准备
- 2. PHP编译前的config配置
- 3. Unix/Linux平台下的编译
- 4. 在Win32平台上编译PHP
- 5. 小结
- 5 Your First Extension
- 1. 一个扩展的基本结构
- 2. 编译我们的扩展
- 3. 静态编译
- 4. 编写函数
- 5. 小结
- 6 函数返回值
- 1. 一个特殊的参数:return_value
- 2. 引用与函数的执行结果
- 3. 小结
- 7 函数的参数
- 1. zend_parse_parameters
- 2. Arg Info 与类型绑定
- 3. 小结
- 8 使用HashTable与{数组}
- 1. 数组(C中的)与链表
- 2. 操作HashTable的API
- 3. 在内核中操作PHP语言中数组
- 4. 小结
- 9 PHP中的资源类型
- 1. 复合类型的数据——{资源}
- 2. Persistent Resources
- 3. {资源}自有的引用计数
- 4. 小结
- 10 PHP中的面向对象(一)
- 1. zend_class_entry
- 2. 定义一个类
- 3. 定义一个接口
- 4. 类的继承与接口的实现
- 5. 小结
- 11 PHP中的面向对象(二)
- 1. 生成对象的实例与调用方法
- 2. 读写对象的属性
- 3. 小结
- 12 启动与终止的那点事
- 2. 小结
- 1. 关于生命周期
- 2. MINFO与phpinfo
- 3. 常量
- 4. PHP扩展中的全局变量
- 5. PHP语言中的超级全局变量
- 6. 小结
- 13 INI设置
- 1. 声明和访问ini设置
- 2. 小结
- 2. 小结
- 14 流式访问
- 1. 概览
- 2. 打开流
- 3. 访问流
- 4. 静态资源操作
- 5. 小结
- 15 流的实现
- 1. php流的表象之下
- 2. 包装器操作
- 3. 实现一个包装器
- 4. 操纵
- 5. 检查
- 6. 小结
- 16 有趣的流
- 1. 上下文
- 2. 过滤器
- 3. 小结
- 17 配置和链接
- 1. autoconf
- 2. 库的查找
- 3. 强制模块依赖
- 4. Windows方言
- 5. 小结
- 18 扩展生成
- 1. ext_skel
- 2. PECL_Gen
- 3. 小结
- 19 设置宿主环境
- 1. 嵌入式SAPI
- 2. 构建并编译一个宿主应用
- 3. 通过嵌入包装重新创建cli
- 4. 老技术新用
- 5. 小结
- 20 高级嵌入式
- 1. 回调到php中
- 2. 错误处理
- 3. 初始化php
- 4. 覆写INI_SYSTEM和INI_PERDIR选项
- 5. 捕获输出
- 6. 同时扩展和嵌入
- 7. 小结
- 约定