基于PHP7的PHP扩展开发之五(数组的处理)

php相关 / 2017年03月23日 13时36分 / 11195人浏览
目的:熟悉数组在PHP扩展里面如何处理 要实现的PHP代码如下:把两个数组,相同key的字符串值拼接。
   $val) {
            if (isset($prefix[$key]) 
                    && is_string($val) 
                    && is_string($prefix[$key])) {
                $arr[$key] = $prefix[$key].$val;
            }   
        }   
        return $arr;
    }

   $arr = array(
        0 => '0',
        1 => '456',
        'a' => 'def',
    );  
    $prefix = array(
        1 => '123',
        'a' => 'abc',
    ); 
    var_dump(array_concat($arr, $prefix));
    ?>
基础代码 在myecho扩展上增加 array_concat 方法。 实现array_concat方法 array_concat方法的PHP扩展源码:
PHP_FUNCTION(array_concat)
{
    zval *arr, *prefix, *entry, *prefix_entry, value;
    zend_string *string_key, *result;
    zend_ulong num_key;

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa", &arr, &prefix) == FAILURE) {
        return;
    }

    array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(arr)));

    ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(arr), num_key, string_key, entry) {
        if (string_key && zend_hash_exists(Z_ARRVAL_P(prefix), string_key)) {
            prefix_entry = zend_hash_find(Z_ARRVAL_P(prefix), string_key);
            if (Z_TYPE_P(entry) == IS_STRING && prefix_entry != NULL && Z_TYPE_P(prefix_entry) == IS_STRING) {
                result = strpprintf(0, "%s%s", Z_STRVAL_P(prefix_entry), Z_STRVAL_P(entry));
                ZVAL_STR(&value, result);
                zend_hash_update(Z_ARRVAL_P(return_value), string_key, &value);
            }   
        } else if (string_key == NULL && zend_hash_index_exists(Z_ARRVAL_P(prefix), num_key)){
            prefix_entry = zend_hash_index_find(Z_ARRVAL_P(prefix), num_key);
            if (Z_TYPE_P(entry) == IS_STRING && prefix_entry != NULL && Z_TYPE_P(prefix_entry) == IS_STRING) {
                result = strpprintf(0, "%s%s", Z_STRVAL_P(prefix_entry), Z_STRVAL_P(entry));
                ZVAL_STR(&value, result);
                zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, &value);
            }
        } else if (string_key) {
            zend_hash_update(Z_ARRVAL_P(return_value), string_key, entry);
            zval_add_ref(entry);
        } else  {
            zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry);
            zval_add_ref(entry);
        }
    }ZEND_HASH_FOREACH_END();

}

找到PHP_FE_END 在上面增加
PHP_FE(array_concat, NULL)
代码说明 PHP中的数组本质上就是一个哈希。 对于哈希处理的方法主要集中在Zend/zend_hash.h中。 对于数组的操作方法主要集中在Zend/API.h。数组的方法其实就是对哈希处理方法的一层包装。 数组操作的方法主要是以add_assoc_ 和 add_index_ 开头的一些列方法。 下面是代码中涉及的一些方法。 zend_hash_num_elements获取数组的元素个数。 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(arr))); 初始化一个数组。在PHP扩展中,我们是通过return_value这个变量设置方法的返回值。因此,我们直接修改这个return_value变量即可。感兴趣的话,可以把宏方法PHP_FUNCTION展开看下。 PHP7提供了一套宏方法用于遍历哈希和对哈希进行操作。这些宏方法主要放在Zend/zend_hash.h文件中。如,代码中的ZEND_HASH_FOREACH_KEY_VAL就是一个变量哈希的宏。是不是和PHP代码中的foreach有点像? 在这里我们把代码中用到的哈希相关的方法做下整理说明: ZEND_HASH_FOREACH_KEY_VAL 和 ZEND_HASH_FOREACH_END 配合使用,实现foreach的效果。 zend_hash_exists 检测指定的key在哈希中是否存在。key为字符串。 zend_hash_index_exists 检测指定的key在哈希中是否存在。key为数字。 zend_hash_find 根据key查找指定的值。key为字符串。 zend_hash_index_find 根据key查找指定的值。key为数字。 zend_hash_update 更新指定key的值。key为字符串。 zend_hash_index_update 更新指定key的值。key为数字。 基本上有这些方法,你就可以对数组进行一些基本操作了。方法命名也很有规律,key为字符串和数字提供了两套。 zval_add_ref(entry); 给数组的值,增加一次引用计数。zend_hash_update方法只自动给string_key自动增加了一次引用计数。数组return_value共用数组arr的值。因此,我们需要手动增加一次引用计数。 PHP7哈希相关的文章大家可以看看 http://jpauli.github.io/2016/04/08/hashtables.html 编译生成扩展 参考《基于PHP7的PHP扩展开发之一(hello word)》 测试
 '0',
        1 => '456',
        'a' => 'def',
    );  
    $prefix = array(
        1 => '123',
        'a' => 'abc',
    );  
    var_dump(array_concat($arr, $prefix));
输出 array(3) { [0]=> string(1) "0" [1]=> string(6) "123456" ["a"]=> string(6) "abcdef" }