php扩展开发 全局变量,PHP扩展中的全局变量

PHP扩展中的全局变量

这一章,我们将学会如何在PHP扩展中使用全局变量。

在扩展中定义全局变量

首先,我们需要在扩展的头文件中(默认是php_*.h)中定义所有的全局变量。举个例子,比如我们要定义一个无符号的long类型的全局变量,我们可以这样定义:

ZEND_BEGIN_MODULE_GLOBALS(sample4)

unsigned long counter;

ZEND_END_MODULE_GLOBALS(sample4)

用ZEND_BEGIN_MODULE_GLOBALS和ZEND_END_MODULE_GLOBALS宏将定义的全局变量包起来。将上例中的宏展开后,是下面这个样子:

typedef struct _zend_sample4_globals {

unsigned long counter;

} zend_sample4_globals;

如果你还有其他的全局变量需要定义,只需加在两个宏之间就可以了。接下来我们该在simple4.c中声明我们在头文件中定义的这些全局变量了:

ZEND_DECLARE_MODULE_GLOBALS(sample4);

这个宏的内部实现取决于是否启用了线程安全,在非线程安全的环境下,如:Apache1,Apache2-prefork, CGI,CLI...会使用zend_sample4_globals结构来定义

全局变量:

zend_sample4_globals sample4_globals;

我们可以直接通过sample4_globals.counter来获取计数器的值。在线程安全的版本中,另一种方法是声明一个整数:

int sample4_globals_id;

填充这个ID就等于定义了扩展中的全局变量。根据其定义的信息,将为每个新线程的独立存储空间分配内存块。我们可以在MINIT中这样定义:

#ifdef ZTS

ts_allocate_id(

&sample4_globals_id,

sizeof(zend_sample4_globals),

NULL, NULL);

#endif

有一点需要注意这种方法需要包裹在#ifdef中,以防止它在没有启动Zend Thread Safety(ZTS)时执行。因为sample4_globals_id只能在多线程环境中使用。非线程

的版本用我们在前面提到的sample4_globals来声明全局变量。

线程中的初始化和关闭

在非线程的环境中,会将一个zend_sample4_globals结构的副本保存在指定进程中。你可以指定他的默认值,或者在MINIT或者RINIT中分配资源来初始化它。要记得

在对应的MSHUTDOWN或者RSHUTDOWN中及时释放这些资源。

然而在线程版本中,一个新的结构会在一个新线程spun的时候被分配。为了知道怎样初始化和关闭扩展中的全局变量,需要向ZE引擎提供回调函数。在前面我们在调用

ts_allocate_id()的时候是是以NULL来作为这个值的,接下来我们添加2个一会需要在MINIT调用的方法:

static void php_sample4_globals_ctor(zend_sample4_globals *sample4_globals TSRMLS_DC)

{

/* Initialize a new zend_sample4_globals struct

* During thread spin-up */

sample4_globals->counter = 0;

}

static void php_sample4_globals_dtor(zend_sample4_globals *sample4_globals TSRMLS_DC)

{

/* Any resources allocated during initialization

* May be freed here */

}

我们在启用和关闭的时候调用它们:

PHP_MINIT_FUNCTION(sample4) {

REGISTER_STRING_CONSTANT("SAMPLE4_VERSION", PHP_SAMPLE4_EXTVER, CONST_CS | CONST_PERSISTENT);

#ifdef ZTS

ts_allocate_id(&sample4_globals_id,

sizeof(zend_sample4_globals),

(ts_allocate_ctor)php_sample4_globals_ctor,

(ts_allocate_dtor)php_sample4_globals_dtor);

#else

php_sample4_globals_ctor(&sample4_globals TSRMLS_CC);

#endif

return SUCCESS;

}

PHP_MSHUTDOWN_FUNCTION(sample4) {

#ifndef ZTS

php_sample4_globals_dtor(&sample4_globals TSRMLS_CC);

#endif

return SUCCESS;

}

现在我们已经知道如何在扩展中创建全局变量了,在不是ZTS的环境中,使用它们很简单,我们还来看前面定义的那个计数器的递增功能如何实现:

PHP_FUNCTION(sample4_counter) {

RETURN_LONG(++sample4_globals.counter);

}

是不是看起来很简单,但是,在线程版本中将无法正常工作。那么我们来看看怎么在线程环境中完成这个功能吧:

PHP_FUNCTION(sample4_counter)

{

#ifdef ZTS

RETURN_LONG(++TSRMG(sample4_globals_id, \

zend_sample4_globals*, counter));

#else

/* non-ZTS */

RETURN_LONG(++sample4_globals.counter);

#endif

}

看起来很丑对吗?想象一下,在你的整个代码库中,这些IFDEF指令在每一个线程安全的全局访问时穿插。它会看起来比Perl更糟糕!这就是为什么所有

的核心扩展,都有使用一个额外的宏观层抽象这种情况。我们可以在php_sample4.h中找到下面这段代码:

#ifdef ZTS

#include "TSRM.h"

#define SAMPLE4_G(v) TSRMG(sample4_globals_id, zend_sample4_globals*, v)

#else

#define SAMPLE4_G(v) (sample4_globals.v)

#endif

使用它们会让你的方法看起来更简洁:

PHP_FUNCTION(sample4_counter) {

RETURN_LONG(++SAMPLE4_G(counter));

}

看到*G()这样的宏是不是有种似曾相识的感觉?也许以前你看到过EG()、CG()等宏,了解他们会让你对PHP的了解更深一步:

Accessor Macro

Associated Data

EG()

这个宏可以用来访问符号表,函数,资源信息和常量。

CG()

用来访问核心全局变量。

PG()

PHP全局变量。我们知道php.ini会映射一个或者多个PHP全局结构。举几个使用这个宏的例子:PG(register_globals), PG(safe_mode), PG(memory_limit)

FG()

文件全局变量。大多数文件I/O或相关的全局变量的数据流都塞进标准扩展出口结构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值