月度归档:2010年03月

PHP源码阅读笔记十四: array_combine函数

PHP源码阅读笔记十四: array_combine函数

array_combine

(PHP 5)
array_combine — 创建一个数组,用一个数组的值作为其键名,另一个数组的值作为其值
说明

array array_combine ( array keys, array values )

返回一个 array,用来自 keys 数组的值作为键名,来自 values 数组的值作为相应的值。
如果两个数组的单元数不同或者数组为空时返回 FALSE。

程序实现说明:

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
array_init(return_value);
 
 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos_keys);
 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos_values);    //    初始化数组指针,将其置为双向链接的头指针
 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&entry_keys, &pos_keys) == SUCCESS &&
   zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&entry_values, &pos_values) == SUCCESS) {    //    同时遍历两个数组
  if (Z_TYPE_PP(entry_keys) == IS_STRING) {    //    如果key值为字符串,以key
   zval_add_ref(entry_values);
   add_assoc_zval_ex(return_value, Z_STRVAL_PP(entry_keys), Z_STRLEN_PP(entry_keys)+1, *entry_values);
  } else if (Z_TYPE_PP(entry_keys) == IS_LONG) {
   zval_add_ref(entry_values);
   add_index_zval(return_value, Z_LVAL_PP(entry_keys), *entry_values);
  } else {
   zval key;
   key = **entry_keys;
   zval_copy_ctor(&key);
   convert_to_string(&key);    //    转化为字符串,如果为数组,则为Array
   zval_add_ref(entry_values);
   add_assoc_zval_ex(return_value, Z_STRVAL(key), Z_STRLEN(key)+1, *entry_values);
   zval_dtor(&key);
  }
  zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos_keys);
  zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos_values);    //    下一个元素,其实现为:pos_values = pos_values->pListNext;
 
 }

在PHP代码中如果key数组中包含两个数组,则后面一个会覆盖前面,即最终只有一个元素,
如下所示PHP代码:

1
2
3
4
5
6
7
\
<?PHP
$arr1 = array(1, array(1, 2), array(3, 4), array(5, 6));
$arr2 = array(33, 44, 55, 66);
$arr3 = array_combine($arr1, $arr2);
print_r($arr3);
die();

此代码会输出:
Array ( [1] => 33 [Array] => 66 )

EOF

PHP源码阅读笔记十三:array_change_key_case,array_chunk

PHP源码阅读笔记十三:array_change_key_case,array_chunk
array_change_key_case

(PHP 4 >= 4.2.0, PHP 5)
array_change_key_case — 返回字符串键名全为小写或大写的数组
说明

array array_change_key_case ( array input [, int case] )

array_change_key_case() 将 input 数组中的所有键名改为全小写或大写。改变是根据后一个选项 case 参数来进行的。可以在这里用两个常量,CASE_UPPER 和 CASE_LOWER。默认值是 CASE_LOWER。本函数不改变数字索引。
看到这个函数,觉得应该是遍历数组所在的hash table,然后将其对应的key值转换成大写或小写(如果是字符串弄的key值)
看完后有一些不同,程序是将每个数组元素的引用都有加一

array_chunk
(PHP 4 >= 4.2.0, PHP 5)
array_chunk — 将一个数组分割成多个
说明

array array_chunk ( array input, int size [, bool preserve_keys] )

array_chunk() 将一个数组分割成多个数组,其中每个数组的单元数目由 size 决定。最后一个数组的单元数目可能会少几个。得到的数组是一个多维数组中的单元,其索引从零开始。
将可选参数 preserve_keys 设为 TRUE,可以使 PHP 保留输入数组中原来的键名。如果你指定了 FALSE,那每个结果数组将用从零开始的新数字索引。默认值是 FALSE。

程序实现说明:

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
array_init(return_value);    //    初始化返回值 数组
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void**)&entry, &pos) == SUCCESS) {    //    遍历HASH TABLE
/* 如果不存在,则创建并初始化chunk */
if (!chunk) {
MAKE_STD_ZVAL(chunk);
array_init(chunk);
}
/* 给数组元素的引用加一,相当于 *entry->refcount++; */
zval_add_ref(entry);
if (preserve_keys) {    //    保留键值
key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &str_key,
&str_key_len, &num_key, 0, &pos);    //    取元素的key值类型,此值是要所元素的nKeyLength属性判断
 
if (key_type == HASH_KEY_IS_STRING) {    //    字符串类型
add_assoc_zval_ex(chunk, str_key, str_key_len, *entry);
} else {
add_index_zval(chunk, num_key, *entry);
}
} else {
add_next_index_zval(chunk, *entry);    //    给返回的子数组添加元素
}
 
if (!(++current % size)) {    //    如果达到分割的界限,则将分割出来创建的子数组添加到返回数组中,并将子数组置为NULl
add_next_index_zval(return_value, chunk);
chunk = NULL;
}
zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);    //    下一个元素
}
if (chunk) {
add_next_index_zval(return_value, chunk);    //    剩余的元素
}