PHP扩展中返回数组源码分析
2014-07-09 18:24
501 查看
最近在公司的工作时负责实现一些PHP扩展。在这些扩展中,经常需要返回数组。我都是这么操作的:
array_init(return_value);
zval* arr;
ALLOC_INIT_ZVAL(arr);
array_init(arr);
add_assoc_long(arr,"num",121);
add_assoc_string(arr,"string",”hello world!”,1);
add_assoc_zval(return_value,"array",arr);
虽然会用,但其实心里一直没底,不知道上面的这个用法是否会出错。
通过今天查看php 5.3的源码,终于知道了,上面的用法是安全的。
要想弄清楚上面的代码到底都干了什么,需要弄明白3个函数——array_init()、ALLOC_INIT_ZVAL和add_assoc_xxx(其实这个有一簇类似的函数,具体的请参考源码zend_API.h文件)。
1. array_init()函数分析
该函数位于zend_API.h中,定义如下:
_array_init()函数定义位于zend_API.c中,负责将arg初始化为一个数组类型的zval,并将arg的类型赋值为IS_ARRAY,具体如下:
_zend_hash_init()函数位于Zend_hash.c中,完成对arg的初始化,其中需要注意的是对persistent这个成员的初始化(该参数决定了是调用操作系统的内存函数还是调用ZendMM来给自己分配内存)。
因为在_array_init()函数中传给_zend_hash_init()函数的persistent参数为0,所以内存分配方式为“非持久性”。
小结:array_init()函数负责将一个zval类型的变量初始化为数组类型,并设置其相关的内存分配方式为“非持久性”。
2. ALLOC_INIT_ZVAL宏分析
ALLOC_INIT_ZVAL负责申请一块空间给zval,然后对其进行初始化,具体定义如下:
ALLOC_ZVAL宏位于Zend_gc.h文件中,调用emalloc申请一块空间给zval,并为PHP垃圾回收机制(详细的请参考《深入理解PHP内核》第六章第四节(http://www.php-internals.com/))对该空间做一些初始化,具体代码如下:
INIT_ZVAL宏位于Zend.h中,主要是对zval结构做一些初始化,具体如下:
3. add_assoc_xxx簇函数分析(以add_assoc_long为例)
add_assoc_long()函数位于zend_API.h中,将一个long值添加到数组中,代码如下:
add_assoc_long_ex()函数位于zend_API.c中,负责将long值转换为PHP中的变量存储结构zval,然后将这个zval添加到数组中。具体代码如下:
MAKE_STD_ZVAL宏位于zend.h中,负责申请一块zval空间并初始化,具体代码如下:
ALLOC_ZVAL的分析上面已经说过了,这里看一下INIT_PZVAL,这个宏也是对zval结构做一些初始化,代码如下:
总结:经过上述3个函数的分析,发现它们所使用的内存都是利用ZendMM机制申请得来的,而且都是“非持久性”内存,所以我们就可以很放心了。因为这些操作所申请的内存会在每次请求后被自动“释放”(其实并没有真正的释放,而是这块内存再次变得可用了)。
array_init(return_value);
zval* arr;
ALLOC_INIT_ZVAL(arr);
array_init(arr);
add_assoc_long(arr,"num",121);
add_assoc_string(arr,"string",”hello world!”,1);
add_assoc_zval(return_value,"array",arr);
虽然会用,但其实心里一直没底,不知道上面的这个用法是否会出错。
通过今天查看php 5.3的源码,终于知道了,上面的用法是安全的。
要想弄清楚上面的代码到底都干了什么,需要弄明白3个函数——array_init()、ALLOC_INIT_ZVAL和add_assoc_xxx(其实这个有一簇类似的函数,具体的请参考源码zend_API.h文件)。
1. array_init()函数分析
该函数位于zend_API.h中,定义如下:
#define array_init(arg) _array_init((arg), 0 ZEND_FILE_LINE_CC)
_array_init()函数定义位于zend_API.c中,负责将arg初始化为一个数组类型的zval,并将arg的类型赋值为IS_ARRAY,具体如下:
ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC) { ALLOC_HASHTABLE_REL(Z_ARRVAL_P(arg)); _zend_hash_init(Z_ARRVAL_P(arg), size, NULL, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC); Z_TYPE_P(arg) = IS_ARRAY; return SUCCESS; }
_zend_hash_init()函数位于Zend_hash.c中,完成对arg的初始化,其中需要注意的是对persistent这个成员的初始化(该参数决定了是调用操作系统的内存函数还是调用ZendMM来给自己分配内存)。
因为在_array_init()函数中传给_zend_hash_init()函数的persistent参数为0,所以内存分配方式为“非持久性”。
小结:array_init()函数负责将一个zval类型的变量初始化为数组类型,并设置其相关的内存分配方式为“非持久性”。
2. ALLOC_INIT_ZVAL宏分析
ALLOC_INIT_ZVAL负责申请一块空间给zval,然后对其进行初始化,具体定义如下:
#define ALLOC_INIT_ZVAL(zp) \ ALLOC_ZVAL(zp); \ INIT_ZVAL(*zp);
ALLOC_ZVAL宏位于Zend_gc.h文件中,调用emalloc申请一块空间给zval,并为PHP垃圾回收机制(详细的请参考《深入理解PHP内核》第六章第四节(http://www.php-internals.com/))对该空间做一些初始化,具体代码如下:
#define ALLOC_ZVAL(z) \ do { \ (z) = (zval*)emalloc(sizeof(zval_gc_info)); \ GC_ZVAL_INIT(z); \ } while (0)
INIT_ZVAL宏位于Zend.h中,主要是对zval结构做一些初始化,具体如下:
#define INIT_ZVAL(z) z = zval_used_for_init;
3. add_assoc_xxx簇函数分析(以add_assoc_long为例)
add_assoc_long()函数位于zend_API.h中,将一个long值添加到数组中,代码如下:
<pre name="code" class="cpp">#define add_assoc_long(__arg, __key, __n) add_assoc_long_ex(__arg, __key, strlen(__key)+1, __n)
add_assoc_long_ex()函数位于zend_API.c中,负责将long值转换为PHP中的变量存储结构zval,然后将这个zval添加到数组中。具体代码如下:
ZEND_API int add_assoc_long_ex(zval *arg, const char *key, uint key_len, long n) /* {{{ */ { zval *tmp; MAKE_STD_ZVAL(tmp); ZVAL_LONG(tmp, n); return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL); }
MAKE_STD_ZVAL宏位于zend.h中,负责申请一块zval空间并初始化,具体代码如下:
#define MAKE_STD_ZVAL(zv) \ ALLOC_ZVAL(zv); \ INIT_PZVAL(zv);
ALLOC_ZVAL的分析上面已经说过了,这里看一下INIT_PZVAL,这个宏也是对zval结构做一些初始化,代码如下:
<pre name="code" class="cpp">#define INIT_PZVAL(z) \ (z)->refcount__gc = 1; \ (z)->is_ref__gc = 0;
总结:经过上述3个函数的分析,发现它们所使用的内存都是利用ZendMM机制申请得来的,而且都是“非持久性”内存,所以我们就可以很放心了。因为这些操作所申请的内存会在每次请求后被自动“释放”(其实并没有真正的释放,而是这块内存再次变得可用了)。
相关文章推荐
- 最近碰到个问题,关于php扩展编程如何返回数组的问题
- PHP扩展程序中返回数组对象
- PHP 扩展返回数组类型
- php数组源码分析
- PHP源码分析-数组
- 关于php扩展编程如何返回数组的问题
- PHP源码分析-数组
- php数组源码分析
- PHP源码分析-数组
- PHP内核探索:数组源码分析
- PHP源码分析-数组
- PHP源码分析-数组
- ECSHOP 源码分析(index.php)
- DEDE源码分析与学习--index.php文件解读
- PHP 文件上传源码分析(RFC1867)
- DEDE源码分析与学习之三: member/archives_add_action.php文件解读
- DEDE源码分析与学习之三: member/archives_*.php文件解读
- 一个PHP数组应该有多大的分析
- php用数组返回无限分类的列表数据的代码
- PHP文件上传源码分析(RFC1867)