所有的宏都有三种形式:一个是接受zval s,另外一个接受zval *s,最后一个接受zval **s。它们的区别是在命名上,第一个没有后缀,zval *有后缀_P(代表一个指针),最后一个 zval **有后缀_PP(代表两个指针)。
现在,你有足够的信息来独立完成 file_read()和 file_write()函数。这里是一个可能的实现:
复制代码 代码如下:
PHP_FUNCTION(file_read){
int argc = ZEND_NUM_ARGS();
long size;
zval *filehandle = NULL;
FILE *fp;
char *result;
size_t bytes_read;
if (zend_parse_parameters(argc TSRMLS_CC, "rl", &filehandle,&size) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(fp, FILE *, &filehandle, -1, "standard-cfile", le_myfile);
result = (char *) emalloc(size+1);
bytes_read = fread(result, 1, size, fp);
result[bytes_read] = '\0';
RETURN_STRING(result, 0);
}
PHP_FUNCTION(file_write){
char *buffer = NULL;
int argc = ZEND_NUM_ARGS();
int buffer_len;
zval *filehandle = NULL;
FILE *fp;
if (zend_parse_parameters(argc TSRMLS_CC, "rs", &filehandle,&buffer, &buffer_len) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(fp, FILE *, &filehandle, -1, "standard-cfile", le_myfile);
if (fwrite(buffer, 1, buffer_len, fp) != buffer_len) {
RETURN_FALSE;
}
RETURN_TRUE;
}
测试扩展
你现在可以编写一个测试脚本来检测扩展是否工作正常。下面是一个示例脚本,该脚本打开文件test.txt,输出文件类容到标准输出,建立一个拷贝test.txt.new。
复制代码 代码如下:
<?php
$fp_in = file_open("test.txt", "r") or die("Unable to open input file\n");
$fp_out = file_open("test.txt.new", "w") or die("Unable to open output file\n");
while (!file_eof($fp_in)) {
$str = file_read($fp_in, 1024);
print($str);
file_write($fp_out, $str);
}
file_close($fp_in);
file_close($fp_out);
?>
全局变量
你可能希望在扩展里使用全局C变量,无论是独自在内部使用或访问php.ini文件中的INI扩展注册标记(INI在下一节中讨论)。因为PHP是为多线程环境而设计,所以不必定义全局变量。PHP提供了一个创建全局变量的机制,可以同时应用在线程和非线程环境中。我们应当始终利用这个机制,而不要自主地定义全局变量。用一个宏访问这些全局变量,使用起来就像普通全局变量一样。
用于生成myfile工程骨架文件的ext_skel脚本创建了必要的代码来支持全局变量。通过检查php_myfile.h文件,你应当发现类似下面的被注释掉的一节,
复制代码 代码如下:
ZEND_BEGIN_MODULE_GLOBALS(myfile)
int global_value;
char *global_string;
ZEND_END_MODULE_GLOBALS(myfile)
你可以把这一节的注释去掉,同时添加任何其他全局变量于这两个宏之间。文件后部的几行,骨架脚本自动地定义一个MYFILE_G(v)宏。这个宏应当被用于所有的代码,以便访问这些全局变量。这就确保在多线程环境中,访问的全局变量仅是一个线程的拷贝,而不需要互斥的操作。
为了使全局变量有效,最后需要做的是把myfile.c:
复制代码 代码如下:
ZEND_DECLARE_MODULE_GLOBALS(myfile)
注释去掉。
你也许希望在每次PHP请求的开始初始化全局变量。另外,做为一个例子,全局变量已指向了一个已分配的内存,在每次PHP请求结束时需要释放内存。为了达到这些目的,全局变量机制提供了一个特殊的宏,用于注册全局变量的构造和析构函数(参考表对宏参数的说明):
复制代码 代码如下:
ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor, globals_dtor)
表 ZEND_INIT_MODULE_GLOBALS 宏参数
参数 含义
module_name 与传递给ZEND_BEGIN_MODULE_GLOBALS()宏相同的扩展名称。
globals_ctor 构造函数指针。在myfile扩展里,函数原形与void php_myfile_init_globals(zend_myfile_globals *myfile_globals)类似
globals_dtor 析构函数指针。例如,php_myfile_init_globals(zend_myfile_globals *myfile_globals)
你可以在myfile.c里看到如何使用构造函数和ZEND_INIT_MODULE_GLOBALS()宏的示例。
添加自定义INI指令
INI文件(php.ini)的实现使得PHP扩展注册和监听各自的INI条目。如果这些INI条目由php.ini、Apache的htaccess或其他配置方法来赋值,注册的INI变量总是更新到正确的值。整个INI框架有许多不同的选项以实现其灵活性。我们涉及一些基本的(也是个好的开端),借助本章的其他材料,我们就能够应付日常开发工作的需要。
通过在PHP_INI_BEGIN()/PHP_INI_END()宏之间的STD_PHP_INI_ENTRY()宏注册PHP INI指令。例如在我们的例子里,myfile.c中的注册过程应当如下:
复制代码 代码如下: