1 PHP_FUNCTION(array_diff)
2 {
3 zval *args;
4 int argc, i;
5 uint32_t num;
6 HashTable exclude;
7 zval *value;
8 zend_string *str, *key;
9 zend_long idx;
10 zval dummy;
11
12 // 至少两个参数
13 if (ZEND_NUM_ARGS() < 2) {
14 php_error_docref(NULL, E_WARNING, "at least 2 parameters are required, %d given", ZEND_NUM_ARGS());
15 return;
16 }
17 // 类型描述符:* variable arguments list (0 or more)
18 // 类型描述符:+ variable arguments list (1 or more)
19 // 参数存放在数组args中,argc保存参数个数
20 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
21 return;
22 }
23
24 // 第一个参数不是数组,则报错
25 if (Z_TYPE(args[0]) != IS_ARRAY) {
26 php_error_docref(NULL, E_WARNING, "Argument #1 is not an array");
27 RETURN_NULL(); // 返回NULL
28 }
29
30 /* count number of elements */
31 // 检查所有参数是否是数组
32 num = 0;
33 for (i = 1; i < argc; i++) {
34 if (Z_TYPE(args[i]) != IS_ARRAY) {
35 php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
36 RETURN_NULL(); // 返回NULL
37 }
38 num += zend_hash_num_elements(Z_ARRVAL(args[i])); // 所有参数数组的元素个数累加
39 }
40
41 // 元素个数num为0,返回第一个参数数组(空数组)
42 if (num == 0) {
43 ZVAL_COPY(return_value, &args[0]);
44 return;
45 }
46
47 ZVAL_NULL(&dummy);
48 /* create exclude map */
49 zend_hash_init(&exclude, num, NULL, NULL, 0);
50 // 从第二个数组开始,所以数组元素保存到exclude
51 for (i = 1; i < argc; i++) {
52 // 遍历数组
53 ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[i]), value) {
54 str = zval_get_string(value); // 数组元素值转为字符串
55 zend_hash_add(&exclude, str, &dummy); //
56 zend_string_release(str);
57 } ZEND_HASH_FOREACH_END();
58 }
59
60 /* copy all elements of first array that are not in exclude set */
61 // 初始化返回值数组,大小和第一个数组一致。
62 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
63 // 循环遍历第一个数组
64 ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL(args[0]), idx, key, value) {
65 str = zval_get_string(value); // 元素值转为字符串
66 if (!zend_hash_exists(&exclude, str)) { // exclude中找不到该值
67 // 插入到返回值数组中(差集),键名保留不变。
68 if (key) {
69 value = zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
70 } else {
71 value = zend_hash_index_add_new(Z_ARRVAL_P(return_value), idx, value);
72 }
73 zval_add_ref(value);
74 }
75 zend_string_release(str);
76 } ZEND_HASH_FOREACH_END();
77
78 zend_hash_destroy(&exclude);
79 }