周梦康 发表于 2016-03-04 8898 次浏览 标签 : PHP 扩展开发

PHP 扩展开发的文章,我均已更新至《TIPI》(下面的博文可能已经过时,以 TIPI 上的内容为准)。

本篇依然还是对鸟哥博客的学习理解整理 http://www.laruence.com/2009/04/28/719.html

什么是全局变量

作用域区,别于局部变量的,不管是在函数内部还是类方法中,都是可以访问以及修改的。

生命周期,当进程开始,全局变量被初始化;进程结束,那么该进程中的全局变量也被销毁了,内存释放。

准备工作

还是采用原型框架的方式,不再多说直接简单说明下

[root@localhost ext]# cat globals_var.proto 
int tipi_get_global_var()
[root@localhost ext]# ./ext_skel --extname=tipi_globals_demo --proto=globals_var.proto

如何创建全局变量

如果下面哪里不明白的地方请对比着完整代码查看。

1. 在ZEND_BEGIN_MODULE_GLOBALS宏和ZEND_END_MODULE_GLOBALS宏之间添加全局变量

在我们用原型模式生产的骨架代码的头文件php_tipi_globals_demo.h中,全局变量使用默认是注释的,需要注释打开

/* 
   Declare any global variables you may need between the BEGIN
   and END macros here:     

ZEND_BEGIN_MODULE_GLOBALS(tipi_globals_demo)
   long  global_value;
   char *global_string;
ZEND_END_MODULE_GLOBALS(tipi_globals_demo)
*/

我们仅仅使用一个long变量作为演示

ZEND_BEGIN_MODULE_GLOBALS(tipi_globals_demo)
   long  global_value;
ZEND_END_MODULE_GLOBALS(tipi_globals_demo)

2. 去掉ZEND_DECLARE_MODULE_GLOBALS的注释,声明全局变量

tipi_globals_demo.c

/* If you declare any globals in php_tipi_globals_demo.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(tipi_globals_demo)
*/

改为

ZEND_DECLARE_MODULE_GLOBALS(tipi_globals_demo)

3. 在 PHP_MINIT_FUNCTION 里注册全局变量

static void php_tipi_globals_demo_init_globals(zend_tipi_globals_demo_globals *tipi_globals_demo_globals)
{
    tipi_globals_demo_globals->global_value = 0;
}
PHP_MINIT_FUNCTION(tipi_globals_demo)
{
    ZEND_INIT_MODULE_GLOBALS(tipi_globals_demo, php_tipi_globals_demo_init_globals, NULL)
    return SUCCESS;
}

4. 在 PHP_RINIT_FUNCTION 里初始化全局变量

php_tipi_globals_demo.h中,有如下定义

#ifdef ZTS
#define TIPI_GLOBALS_DEMO_G(v) TSRMG(tipi_globals_demo_globals_id, zend_tipi_globals_demo_globals *, v)
#else
#define TIPI_GLOBALS_DEMO_G(v) (tipi_globals_demo_globals.v)
#endif

该宏的定义将是否处于TSRMG(Thread Safe Resource Management)与扩展代码解耦。我们无需关心是否处于TSRMG模式,都直接使用

TIPI_GLOBALS_DEMO_G(v)

来访问修改全局变量v

因为全局变量的初始化,使用都是在执行PHP脚本的过程中。所以应该在PHP_RINIT_FUNCTION阶段初始化,(PHP_MINIT_FUNCTION阶段是模块初始化阶段,负责的后期整个PHP环境的初始化,具体请参考PHP生命周期

根据上面我们添加的全局变量名为global_value,使用ZEND_INIT_MODULE_GLOBALS宏加上构造函数

PHP_RINIT_FUNCTION(tipi_globals_demo)
{
	TIPI_GLOBALS_DEMO_G(global_value) = 10;
	return SUCCESS;
}

5. 使用全局变量

我们在原型中定义了一个函数,名为tipi_get_global_var,我们将其补充完整,其功能就是调用一次加1。

PHP_FUNCTION(tipi_get_global_var)
{
   TIPI_GLOBALS_DEMO_G(global_value)++;
   RETURN_LONG(TIPI_GLOBALS_DEMO_G(global_value));
}

编译并测试

这里简单带过,附带我的执行过程

[root@localhost tipi_globals_demo]# /usr/local/php5/bin/phpize
...
[root@localhost tipi_globals_demo]# ./configure --with-php-config=/usr/local/php5/bin/php-config
...
[root@localhost tipi_globals_demo]# make
...
[root@localhost tipi_globals_demo]# make install

测试

[root@localhost no-debug-non-zts-20121212]# /usr/local/php5/bin/php -d"extension=tipi_globals_demo.so" -r "var_dump(tipi_get_global_var());var_dump(tipi_get_global_var());"
int(1)
int(2)

原理解析

1. 对于ZEND_BEGIN_MODULE_GLOBALSZEND_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_BEGIN_MODULE_GLOBALS(tipi_globals_demo)
   long  global_value;
ZEND_END_MODULE_GLOBALS(tipi_globals_demo)

等价于

typedef struct _zend_tipi_globals_demo_globals {
	long  global_value;
} zend_tipi_globals_demo_globals;

2. ZEND_DECLARE_MODULE_GLOBALS宏的声明

#ifdef ZTS

#define ZEND_DECLARE_MODULE_GLOBALS(module_name)							\
	ts_rsrc_id module_name##_globals_id;

#else

#define ZEND_DECLARE_MODULE_GLOBALS(module_name)							\
	zend_##module_name##_globals module_name##_globals;

#endif

是否线程安全,后面我再单独做一篇笔记(PHP5扩展开发之线程安全),这里先说非多线程的情况,这里相当于在文件前面声明了一个变量

zend_tipi_globals_demo_globals tipi_globals_demo_globals;

3. 所以就有了后面读取全局变量宏的定义

#define TIPI_GLOBALS_DEMO_G(v) (tipi_globals_demo_globals.v)

4. 多线程的情况,请看PHP5扩展开发之线程安全

评论列表

回复 梦康 2016-03-05 13:59:18
没错,就这么简单!