微信号:we21cto

介绍:21CTO(21CTO.com)是中国项级技术专家的学习与服务平台.我们为CTO、技术总监、架构师等技术专家提供高质量的资讯、问答、活动等产品,同时与企业连接,提供技术咨询、研发、运维、技术支持、培训及人才招聘等服...

PHP7扩展开发之数组处理

2016-12-05 23:54 21CTO

各位朋友好。今天给大家的文章仍然锁定PHP领域,主题为PHP内部对数组的处理。PHP的数组的神奇之处,可以支持关联数组和索引数组,这对于其它语言如Java等无法想像的灵活。内部到底啥样,请看由淘宝网技术专家苍老师投的第二稿。ejoy it : -)

前言

这次,我们将演示如何在PHP扩展中如何对数组进行处理。要实现的PHP代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
function array_concat ( $arr , $prefix ) {
     foreach ( $arr as $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 => '123' ,
     'a' => 'abc' ,
); 
$prefix = array (
     1 => '456' ,
     'a' => 'def' ,
); 
var_dump(array_concat( $arr , $prefix ));
?>

把两个数组,相同key的字符串值拼接。

代码奉上:

基础代码

这个扩展,我们将在say扩展上增加 array_concat 方法。say扩展相关代码大家请看这篇文章。PHP7扩展开发之hello word 文中已经详细介绍了如何创建一个扩展和提供了源码下载。

实现array_concat方法

array_concat方法的PHP扩展源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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中的数组本质上就是一个哈希。
对于哈希处理的方法主要集中在
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

我们下篇接着聊。


作者:信海龙(21CTO社区会员)

博客:www.bo56.com


 
21CTO 更多文章 PHP7扩展开发之字符串处理 个性化推荐系统架构设计(三)— 使用爬虫抓取网页与RSS内容 个性化推荐系统(三)— 构建爬虫开发函数基础库 个性化推荐系统(三)— 构建爬虫开发函数基础库 个性化推荐系统架构设计(二):爬虫系统概述
猜您喜欢 程序员的调侃:佛祖保佑,永无BUG 关于Preload,你应该知道些什么? 为什么大型网站前端使用 PHP 后台逻辑用 Java? PostgreSQL中BRIN和BTREE索引的使用(二) 技术牛人告诉你怎样高效度过大学生活——美团点评最佳新人席铭专访