PHP扩展开发-04-全局变量以及部分宏分析

1.1     抛砖引玉

将这一节的目的是想交给大家,如和声明一个变量。使得这个变量针对每次请求独立,也就是说,同一次请求我们访问的变量是同一个,不同的请求我们使用的变量不是同一个。

说道这里我先抛出一个问题:既然要实现上面的要求,那么我们该怎么办呢?我应该在哪里声明我的全局变量呢?

还记得SAPI简介那一张吗?SAPI的实现有三种方式,单进程,多进程,多线程,但是对于每一次而言,都必须执行的几个过程为RINIT RSHUTDOWN….说道这里你意识到了吗。我们是不是在RINIT过程的时候初始化我们的全局常量,这样每次请求的时候这个变量的值都会变成默认值。还没有看明白?看看下面的流程你也许就懂了。

1.      首先在.h文件中声明全局变量

2.      在RINIT过程时初始化这个变量

3.      调用变量

1.2     实现方式

我们还是直接上源代码:我把一些无用的注释去掉了,希望大家别介意

头文件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));

}

 

1.3     结果验证

修改完成后,编译安装我们的扩展,执行下面的命令进行测试

php -r "echotest_global_value(); test_global_value();"

以后我们可能不在对这些简单的结果进行验证了,但是为了学习效果,建议大家自己验证一下。

1.4     实现原理

1.4.1    知识点1

我们先看一下头文件中声明全局变量的两个宏

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的成员变量。

1.4.2    知识点2

我们再来看一下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;

1.4.3    知识点3

在一个宏声明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是一个回调函数指针,这里不再多说。

1.4.4    知识点

我们再来看一下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

你可能感兴趣的:(PHP扩展开发-04-全局变量以及部分宏分析)