php内置函数分析array_diff()
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 }