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_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_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)