将这一节的目的是想交给大家,如和声明一个变量。使得这个变量针对每次请求独立,也就是说,同一次请求我们访问的变量是同一个,不同的请求我们使用的变量不是同一个。
说道这里我先抛出一个问题:既然要实现上面的要求,那么我们该怎么办呢?我应该在哪里声明我的全局变量呢?
还记得SAPI简介那一张吗?SAPI的实现有三种方式,单进程,多进程,多线程,但是对于每一次而言,都必须执行的几个过程为RINIT RSHUTDOWN….说道这里你意识到了吗。我们是不是在RINIT过程的时候初始化我们的全局常量,这样每次请求的时候这个变量的值都会变成默认值。还没有看明白?看看下面的流程你也许就懂了。
1. 首先在.h文件中声明全局变量
2. 在RINIT过程时初始化这个变量
3. 调用变量
我们还是直接上源代码:我把一些无用的注释去掉了,希望大家别介意
头文件php-iamnew.h
#ifndef PHP_IAMNEW_H
#define PHP_IAMNEW_H
extern zend_module_entry iamnew_module_entry;
#define phpext_iamnew_ptr &iamnew_module_entry
#ifdef PHP_WIN32
# definePHP_IAMNEW_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
# definePHP_IAMNEW_API __attribute__ ((visibility("default")))
#else
# definePHP_IAMNEW_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(iamnew);
PHP_MSHUTDOWN_FUNCTION(iamnew);
PHP_RINIT_FUNCTION(iamnew);
PHP_RSHUTDOWN_FUNCTION(iamnew);
PHP_MINFO_FUNCTION(iamnew);
PHP_FUNCTION(confirm_iamnew_compiled); /* For testing, remove later. */
ZEND_BEGIN_MODULE_GLOBALS(iamnew)
long counter;
ZEND_END_MODULE_GLOBALS(iamnew)
#ifdef ZTS
#define IAMNEW_G(v) TSRMG(iamnew_globals_id,zend_iamnew_globals *, v)
#else
#define IAMNEW_G(v) (iamnew_globals.v)
#endif
#endif
PHP_FUNCTION(test_global_value);
源文件iamnew.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_iamnew.h"
ZEND_DECLARE_MODULE_GLOBALS(iamnew) //声明全局变量
static int le_iamnew;
const zend_function_entry iamnew_functions[]= {
PHP_FE(test_global_value,NULL)
{NULL,NULL,NULL} //此处修改以后不再解释
};
zend_module_entry iamnew_module_entry ={
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"iamnew",
iamnew_functions,
PHP_MINIT(iamnew),
PHP_MSHUTDOWN(iamnew),
PHP_RINIT(iamnew),
PHP_RSHUTDOWN(iamnew),
PHP_MINFO(iamnew),
#if ZEND_MODULE_API_NO >= 20010901
"0.1",
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_IAMNEW
ZEND_GET_MODULE(iamnew)
#endif
// 这个函数之前是被注释的,去掉注释,并且函数内容为空即可
static void php_iamnew_init_globals(zend_iamnew_globals*iamnew_globals)
{
}
PHP_MINIT_FUNCTION(iamnew)
{
ZEND_INIT_MODULE_GLOBALS(iamnew, php_iamnew_init_globals,NULL);
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(iamnew)
{
return SUCCESS;
}
PHP_RINIT_FUNCTION(iamnew)
{
IAMNEW_G(counter)= 0; //初始化
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(iamnew)
{
return SUCCESS;
}
PHP_MINFO_FUNCTION(iamnew)
{
php_info_print_table_start();
php_info_print_table_header(2,"iamnew support","enabled");
php_info_print_table_end();
}
// 增加测试函数
PHP_FUNCTION(test_global_value)
{
IAMNEW_G(counter)++;
RETURN_LONG(IAMNEW_G(counter));
}
修改完成后,编译安装我们的扩展,执行下面的命令进行测试
php -r "echotest_global_value(); test_global_value();"
以后我们可能不在对这些简单的结果进行验证了,但是为了学习效果,建议大家自己验证一下。
我们先看一下头文件中声明全局变量的两个宏
ZEND_BEGIN_MODULE_GLOBALS
ZEND_END_MODULE_GLOBALS
我们看一下这两个宏的展开内容:
#define ZEND_BEGIN_MODULE_GLOBALS(module_name) \
typedef struct _zend_##module_name##_globals {
#define ZEND_END_MODULE_GLOBALS(module_name) \
}zend_##module_name##_globals;
从展开信息中我们可以看到,这两个宏仅仅是定了一个叫做zend_##module##_globals的结构体,而ZEND_BEGIN_MODULE_GLOBALS和ZEND_END_MODULE_GLOBALS就是结构体zend_##module##_globals的成员变量。
我们再来看一下ZEND_DECLARE_MODULE_GLOBALS这句话是
#define ZEND_DECLARE_MODULE_GLOBALS(module_name) \
ts_rsrc_idmodule_name##_globals_id;
其实ts_rsrc_id就是int类型,查看ts_rsrc_id的定义就可以知道:typedef int ts_rsrc_id;
在一个宏声明ZEND_INIT_MODULE_GLOBALS,查看一下这个宏的定义
#define ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor,globals_dtor) \
ts_allocate_id(&module_name##_globals_id,sizeof(zend_##module_name##_globals), (ts_allocate_ctor) globals_ctor,(ts_allocate_dtor) globals_dtor);
从定义来看,ZEND_INIT_MODULE_GLOBALS给变量module_name##_globals_id分配了一个id,这个id是一个线程安全的资源id。而module_name##_globals_id不就是ZEND_DECLARE_MODULE_GLOBALS分配的变量吗!
globals_ctor是一个回调函数指针,这里不再多说。
我们再来看一下IAMNEW_G这个宏的定义
#ifdef ZTS //是否线程安全
#defineIAMNEW_G(v) TSRMG(iamnew_globals_id,zend_iamnew_globals *, v)
#else
#defineIAMNEW_G(v) (iamnew_globals.v)
#endif
----------------------------------------------------
TSRMG的定义为:
#define TSRMG(id, type, element) (((type) (*((void ***)tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element)
tsrm_ls的定义为:
void ***tsrm_ls;
从宏整体的定义可以看出IAMNEW_G是取得变量的值。
其实IAMNEW_G就是取的全局变量的值。
如果你对TSRMG非常感兴趣的话,也可以看看这个宏具体的实现方式,不多对于新手来说的确有点困难。
author iamnew<[email protected]>
QQ:947847775