php array_diff 比较两个数组bug避坑 深入了解

今天实用array_diff出现的异常问题,预想的结果应该是返回 "integral_initiate"=>"0",实际没有

先看测试代码:

php 复制代码
$a = [
    "user_name"=>"测","see_num"=>0,"integral_initiate"=>"0"
];
$b = [
    "user_name"=>"测","see_num"=>0,"integral_initiate"=>10
];
$gf = array_diff($a,$b);
print_r($gf);

没有返回差异,纠结了好一阵子又查阅了文档看到这一句话才醒悟

我们简化一下数组来看,通过简化数组发现只要两个数组中间都带有0的值就不会正常效验

解决方案就是换成 array_diff_assoc 对比键名与键值

------------序言--------------

虽然上面得到了想要的结果,但是本着刨根问底的思想继续研究了 一番,查了一些资料,也翻了下源码终于找到了一个合理的解释

复制代码
/* {{{ proto array array_diff(array arr1, array arr2 [, array ...])
   Returns the entries of arr1 that have values which are not present in any of the others arguments. */
PHP_FUNCTION(array_diff)
{
	zval *args;
	int argc, i;
	uint32_t num;
	HashTable exclude;
	zval *value;
	zend_string *str, *tmp_str, *key;
	zend_long idx;
	zval dummy;

	if (ZEND_NUM_ARGS() < 2) {
		php_error_docref(NULL, E_WARNING, "at least 2 parameters are required, %d given", ZEND_NUM_ARGS());
		return;
	}

	ZEND_PARSE_PARAMETERS_START(1, -1)
		Z_PARAM_VARIADIC('+', args, argc)
	ZEND_PARSE_PARAMETERS_END();

	if (Z_TYPE(args[0]) != IS_ARRAY) {
		php_error_docref(NULL, E_WARNING, "Expected parameter 1 to be an array, %s given", zend_zval_type_name(&args[0]));
		RETURN_NULL();
	}

	num = zend_hash_num_elements(Z_ARRVAL(args[0]));
	if (num == 0) {
		for (i = 1; i < argc; i++) {
			if (Z_TYPE(args[i]) != IS_ARRAY) {
				php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(&args[i]));
				RETURN_NULL();
			}
		}
		RETURN_EMPTY_ARRAY();
	} else if (num == 1) {
		int found = 0;
		zend_string *search_str, *tmp_search_str;

		value = NULL;
		ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[0]), value) {
			break;
		} ZEND_HASH_FOREACH_END();

		if (!value) {
			for (i = 1; i < argc; i++) {
				if (Z_TYPE(args[i]) != IS_ARRAY) {
					php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(&args[i]));
					RETURN_NULL();
				}
			}
			RETURN_EMPTY_ARRAY();
		}

		search_str = zval_get_tmp_string(value, &tmp_search_str);

		for (i = 1; i < argc; i++) {
			if (Z_TYPE(args[i]) != IS_ARRAY) {
				php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(&args[i]));
				RETURN_NULL();
			}
			if (!found) {
				ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[i]), value) {
					str = zval_get_tmp_string(value, &tmp_str);
					if (zend_string_equals(search_str, str)) {
						zend_tmp_string_release(tmp_str);
						found = 1;
						break;
					}
					zend_tmp_string_release(tmp_str);
				} ZEND_HASH_FOREACH_END();
			}
		}

		zend_tmp_string_release(tmp_search_str);

		if (found) {
			RETVAL_EMPTY_ARRAY();
		} else {
			ZVAL_COPY(return_value, &args[0]);
		}
		return;
	}

	/* count number of elements */
	num = 0;
	for (i = 1; i < argc; i++) {
		if (Z_TYPE(args[i]) != IS_ARRAY) {
			php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(&args[i]));
			RETURN_NULL();
		}
		num += zend_hash_num_elements(Z_ARRVAL(args[i]));
	}

	if (num == 0) {
		ZVAL_COPY(return_value, &args[0]);
		return;
	}

	ZVAL_NULL(&dummy);
	/* create exclude map */
	zend_hash_init(&exclude, num, NULL, NULL, 0);
	for (i = 1; i < argc; i++) {
		ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[i]), value) {
			str = zval_get_tmp_string(value, &tmp_str);
			zend_hash_add(&exclude, str, &dummy);
			zend_tmp_string_release(tmp_str);
		} ZEND_HASH_FOREACH_END();
	}

	/* copy all elements of first array that are not in exclude set */
	array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
	ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL(args[0]), idx, key, value) {
		str = zval_get_tmp_string(value, &tmp_str);
		if (!zend_hash_exists(&exclude, str)) {
			if (key) {
				value = zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
			} else {
				value = zend_hash_index_add_new(Z_ARRVAL_P(return_value), idx, value);
			}
			zval_add_ref(value);
		}
		zend_tmp_string_release(tmp_str);
	} ZEND_HASH_FOREACH_END();

	zend_hash_destroy(&exclude);
}
/* }}} */

这就可以解释为什么使用array_diff 不能得到想要的结果,因为只要第一个数组中的值在第二个数组中出现过就不算差异,所以并不是bug,反过来再去看一下文档上面英文注释是这样写的

我只能说这个中文版的翻译有待提升,至此问题就到这里了

相关文档:

1、问题解答: https://stackoverflow.com/questions/4742405/array-diff-to-compare-two-associative-arrays/4742438#4742438 2、PHP 如何查看php函数源码-CSDN博客

3、源码地址 :GitCode - 开发者的代码家园

相关推荐
懂点Tech1 小时前
ctfshow misc28:GIF 高度修改解题与脚本实现
开发语言·windows·python
comedate2 小时前
SMLib 的 Examples 导读:PyAPI / SM_API / SMLib 三组示例怎么读
python·cad·smlib·examples·sm_api
云和数据.ChenGuang2 小时前
Python 重写(Override)深度解析:从 MRO 到 super() 的完整机制
java·开发语言·人工智能·python·langchain·1024程序员节
摇滚侠2 小时前
《On Java 中文版 基础卷》阅读笔记 实现隐藏 12
java·数据库·笔记
川石课堂软件测试2 小时前
学习软件测试需掌握的一些知识
数据库·python·sql·功能测试·网络协议·mysql·http
万化冥合3 小时前
PyBox屏幕键盘如何辅助演示键盘操作?
python·计算机外设
车软学堂3 小时前
从测试转开发,到底要补什么
网络·人工智能·python·功能测试·单片机·车载系统·自动化
天空依然蔚蓝3 小时前
分享一个自动检测网站在线状态的python程序
python·运维开发·1024程序员节
岁月宁静3 小时前
一个 AI 项目从本地到上线,要经过哪些步骤?全流程讲清楚
python·docker·agent
codists4 小时前
《crafting interpreters》阅读笔记:p45-p45
python