PHP7 扩展开发(七) 数组

编辑于 2016-10-05

* 移动设备下, 可左滑手指以查看较宽代码

PHP 强大的数组基于HashTable, 以实现快速定位. 同时, 每个 HashTable 中维持了一个双向链表, 以实现FIFO(先进先出)模式. 比如 foreach 就利用了此特征.

foreach 通过移动其双向链表的指针来顺序遍历成员, 也就是说, foreach 执行完毕后, 内置指针会指向数组最后. 即 current($array) 的值会改变.

在 PHP7 中, foreach 执行后不会改变数组指针.

使用 HashTable

略过. 以后可能会补上.

创建数组

HashTable 的使用较为繁琐, 创建数组则有方便的内置宏可用.

//return_value 是 zval* 类型的, 把它初始化成了一个空数组。
ZEND_FUNCTION(sample_array)
{
    array_init(return_value);
} 

可用的内置宏:

//add_assoc_*系列函数
add_assoc_null(zval *aval, char *key);
add_assoc_bool(zval *aval, char *key, zend_bool bval);
add_assoc_long(zval *aval, char *key, long lval);
add_assoc_double(zval *aval, char *key, double dval);
add_assoc_string(zval *aval, char *key, char *strval, int dup);
add_assoc_stringl(zval *aval, char *key,char *strval, uint strlen, int dup);
add_assoc_zval(zval *aval, char *key, zval *value);
 
//备注:其实这些函数都是宏,都是对 add_assoc_*_ex 函数的封装。
 
//add_index_*系列函数
ZEND_API int add_index_long     (zval *arg, ulong idx, long n);
ZEND_API int add_index_null     (zval *arg, ulong idx           );
ZEND_API int add_index_bool     (zval *arg, ulong idx, int b    );
ZEND_API int add_index_resource (zval *arg, ulong idx, int r    );
ZEND_API int add_index_double   (zval *arg, ulong idx, double d);
ZEND_API int add_index_string   (zval *arg, ulong idx, const char *str, int duplicate);
ZEND_API int add_index_stringl  (zval *arg, ulong idx, const char *str, uint length, int duplicate);
ZEND_API int add_index_zval     (zval *arg, ulong index, zval *value);
 
//add_next_index_long函数
ZEND_API int add_next_index_long        (zval *arg, long n  );
ZEND_API int add_next_index_null        (zval *arg          );
ZEND_API int add_next_index_bool        (zval *arg, int b   );
ZEND_API int add_next_index_resource    (zval *arg, int r   );
ZEND_API int add_next_index_double      (zval *arg, double d);
ZEND_API int add_next_index_string      (zval *arg, const char *str, int duplicate);
ZEND_API int add_next_index_stringl     (zval *arg, const char *str, uint length, int duplicate);
ZEND_API int add_next_index_zval        (zval *arg, zval *value);

每组的最后的一个, 即 *_zval() 宏, 允许我们向这个数组中添加资源、对象、数组等复合类型的 PHP 变量. 例子:

ZEND_FUNCTION(sample_array)
{
    zval *subarray;
 
    array_init(return_value);
     
    /* Add some scalars */
    add_assoc_long(return_value, "life", 42);
    add_index_bool(return_value, 123, 1);
    add_next_index_double(return_value, 3.1415926535);
     
    /* Toss in a static string, dup'd by PHP */
    add_next_index_string(return_value, "Foo", 1);
     
    /* Now a manually dup'd string */
    add_next_index_string(return_value, estrdup("Bar"), 0);
 
    /* Create a subarray */
    MAKE_STD_ZVAL(subarray);
    array_init(subarray);
     
    /* Populate it with some numbers */
    add_next_index_long(subarray, 1);
    add_next_index_long(subarray, 20);
    add_next_index_long(subarray, 300);
     
    /* Place the subarray in the parent */
    add_index_zval(return_value, 444, subarray);
}

这时, 在 PHP 中使用 var_dump(sample_array()); , 就会输出:

array(6)
{
    ["life"]=> int(42)
    [123]=> bool(true)
    [124]=> float(3.1415926535)
    [125]=> string(3) "Foo"
    [126]=> string(3) "Bar"
    [444]=> array(3)
    {
        [0]=> int(1)
        [1]=> int(20)
        [2]=> int(300)
    }
}