PHP中比较数组的时候发生了什么?
首先还是从代码来看,我们通过比较运算符号来对两个数组进行比较:
var_dump([1, 2] == [2, 1]); // false
var_dump([1, 2, 3] > [3, 2, 1]); // false
var_dump([5, 6, 7] > [1, 2, 3, 4]); // false
第一组:仔细看,从一眼看过去的正常角度来说,代码中对比的数组其实是一样的数组,[1, 2]和[2, 1]都是两个包含两个元素的数组,元素内容也是一样的,但是,他们的位置不一样。
第二组:同样是位置不一样,[1, 2, 3]是小于[3, 2, 1]的
第三组:[5, 6, 7]每个元素都大于[1, 2, 3, 4],但结果是没有后一个数组大。
相信不少同学已经看出一些端倪了。数组之间的操作符比较是先进行元素数量对比,然后再对比每个键值。官方文档上的解释为:
具有较少成员的数组较小,如果运算数 1 中的键不存在于运算数 2 中则数组无法比较,否则挨个值比较
<?php
// 数组用标准比较运算符这样比较的
function standard_array_compare($op1, $op2)
{
if (count($op1) < count($op2)) {
return -1; // $op1 < $op2
} elseif (count($op1) > count($op2)) {
return 1; // $op1 > $op2
}
foreach ($op1 as $key => $val) {
if (!array_key_exists($key, $op2)) {
return null; // uncomparable
} elseif ($val < $op2[$key]) {
return -1;
} elseif ($val > $op2[$key]) {
return 1;
}
}
return 0; // $op1 == $op2
}
上述代码就是php中使用比较操作符进行数组比较时的代码,首先是count数组的元素数量,如果数组1大于数组2就返回1,否则返回-1。如果相等的话,遍历每一个元素进行对比,如果数组1的某个键值不存在在数组2中,返回null,如果数组1的某个键的值大于数组2的这个键的值,返回1,否则返回-1。遍历的元素也都相同的情况下,最后返回0表示相等。
使用普通的比较操作符对比键值对形式的数组效果会好一些,因为是以固定的键来进行比对,不是以数组下标:
var_dump(['a'=>1, 'b'=>2] == ['b'=>2, 'a'=>1]); // ture
var_dump(['a'=>1, 'b'=>2] == ['a'=>2, 'b'=>1]); // false
var_dump(['a' => 1, 'b' => 5] < ['a' => 2, 'b' => 1]); // true
注意第三条比较,我们的第一个数组的b元素是大于第二个数组的,但通过上面的数组比较代码可以看出,当第一个元素比较结果已经出现了大于小于的情况时,直接就return返回了结果,后面的元素不会再进行比较了。
那么多维数组呢?
var_dump([['aa' => 1], ['bb' => 1, 'dd'=>2]] == [['aa' => 2], ['bb' => 1]]); // false
var_dump([['aa' => 1], ['bb' => 1, 'dd'=>2]] < [['aa' => 2], ['bb' => 1]]); // true
var_dump([['aa' => 1], ['bb' => 1, 'dd'=>2]] < [['aa' => 1, 'cc' => 1], ['bb' => 1]]); // true
子数组会递归进行比较,比较规则依然是按照默认的数组操作符比较方式进行。
弄清楚了数组的比较是如何进行的,那么问题来了,假设前端传给我们的数据是这样的:
[
'John',
'178cm',
'62kg',
]
而我们数据库里存的是:
[
'62kg',
'John',
'178cm',
]
这时如果直接比对两个数组内容,或者直接用json字符串比对,他们都是不相同的,这可怎么办呢?试试自定义一个对比方法吧!
function array_equal($a, $b)
{
return (is_array($a) && is_array($b) && array_diff($a, $b) === array_diff($b, $a));
}
$arr1 = [
'John',
'178cm',
'62kg',
];
$arr2 = [
'62kg',
'John',
'178cm',
];
var_dump(array_equal($arr1, $arr2)); // true
// 元素不一样的话
$arr2 = [
'62kg',
'John Jobs',
'178cm',
];
var_dump(array_equal($arr1, $arr2)); // false
// 再弄乱一点
$arr1 = [
[
'55kg',
'Bob',
'172cm',
[
'employee',
],
],
[
'John',
'178cm',
'62kg',
[
'manager',
],
],
];
$arr2 = [
[
'62kg',
'John',
'178cm',
[
'manager',
],
],
[
[
'employee',
],
'55kg',
'172cm',
'Bob',
],
];
var_dump(array_equal($arr1, $arr2)); // true
其实就是利用了array_diff()这个函数,它的作用是取两个数组的差集,然后再对比两个数组差集的结果来判断两个数组是否相等。这个方法适用于下标数组的比对,但不适用于键值对数组的比对,array_diff()只是取值的差集结果集,不会比对键,所以对于键值对的数组直接使用比较操作符就好啦!
对于数组的比较我们只要弄清楚它的原理就可以了,如果原理不清楚很可能就会埋下隐藏的BUG。数组的比较一定要记住这三点:
1.先比较元素数量
2.再比较每一个元素(多维数组递归比较)
3.先后顺序,第一个有比较结果了后面就不会继续比较了,全部都相等才会返回相等
参考链接:https://www.php.net/manual/zh/language.operators.comparison.php
===============
关注公众号:【硬核项目经理】获取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料
知乎、公众号、抖音、头条搜索【硬核项目经理】
B站ID:482780532
PHP中比较数组的时候发生了什么?的更多相关文章
- JavaScript中的数组详解
JavaScript中的数组 一.数组的定义 数组是值的有序集合,或者说数组都是数据的有序列表. 二.创建数组 [字面量形式] 1.空数组 var arr=[]; 2.带有元素的数组 var arr= ...
- Java中的数组与集合
此文转载自:http://student-lp.iteye.com/blog/2082362 在java编程的过程中,我们不能确定某一类型的对象到底会需要多少,为了解决这个问题,java提供了容纳对象 ...
- c#中的数组、ArrayList、List区别【转】
首先说明C#中的Array类:Array 类是 C# 中所有数组的基类,它是在 System 命名空间中定义.Array 类提供了各种用于数组的属性和方法.关于Array类的一些属性及方法详见博文:C ...
- 【java】解析java中的数组
目录结构: contents structure [+] 一维数组 1,什么是一维数组 2,声明一维数组的三种方式 二维数组 1,什么是二维数组 2,声明二维数组的3种方式 3,二维数组的遍历示例 数 ...
- c#中的数组、ArrayList、List区别
首先说明C#中的Array类:Array 类是 C# 中所有数组的基类,它是在 System 命名空间中定义.Array 类提供了各种用于数组的属性和方法.关于Array类的一些属性及方法详见博文:C ...
- Java中的数组和方法
3.1 数组的定义和使用 数组(Array)是用来存储一组相同数据类型数据的集合.数组中的每个数据称为一个元素(element),数组可以分为一维数组,二维数组和多维数组.我们 主要讲解一维数组和二维 ...
- Java基础学习总结(67)——Java接口API中使用数组的缺陷
如果你发现在一个接口使用有如下定义方法: public String[] getParameters(); 那么你应该认真反思.数组不仅仅老式,而且我们有合理的理由避免暴露它们.在这篇文章中,我将试图 ...
- JavaScript中的数组创建
JavaScript中的数组创建 数组是一个包含了对象或原始类型的有序集合.很难想象一个不使用数组的程序会是什么样. 以下是几种操作数组的方式: 初始化数组并设置初始值 通过索引访问数组元素 添加新元 ...
- JavaScript中Array(数组) 对象
JavaScript中Array 对象 JavaScript中创建数组有两种方式 (一)使用直接量表示法: var arr4 = []; //创建一个空数组var arr5 = [20]; // 创建 ...
随机推荐
- 你认为的.NET数据库连接池,真的是全部吗?
一般我们的项目中会使用1到2个数据库连接配置,同程艺龙的数据库连接配置被收拢到统一的配置中心,由DBA统一配置和维护,业务方通过某个字符串配置拿到的是Connection对象. DBA能在对业务方无侵 ...
- 慕慕生鲜上线&&腾讯云服务器配置准备
1.购买服务器并配置环境 1.1 购买 618购买了腾讯云服务器三年最低配置(1核2G 1Mbps 50G云盘),一时激动忘记了购买前领优惠券,痛失25元. 1.2 环境配置 系统是 CentOS L ...
- 有关SQL注入的一些小知识点
1.判断注入点: 本质原理是找一个需要后台处理后,提交给数据库的点,我理解为用户可以控制并输入后台数据库的变量,比如我们DVWA SQL injection 的ID ,我们可以通过闭合单引号,#注释 ...
- SpringBoot中Jackson的过滤使用
在接口的返回对象中,可能会有一些属性为null或者需要禁止某些字段返回给客户端. 在SpringBoot中可使用内置了Jackson实现这个需求 1. 过滤为null字段 在实体类中使用@JsonIn ...
- @Profile-根据不同环境注入bean
介绍 @Profile元注解是在不同的生产环境中,@Bean创建的SpringBean根据spring.profiles.active指定的环境不同创建不同环境的bean对象 一.@Profile元注 ...
- 详解 OpenGL ES 2.x 渲染流程
khronos官方对OpenGL ES的描述如下: OpenGL ES is a royalty-free, cross-platform API for rendering advanced 2D ...
- Redis缓存雪崩、缓存穿透、热点key
转载自 https://blog.csdn.net/wang0112233/article/details/79558612 https://www.sohu.com/a/230787856_231 ...
- Linkerd 2.10(Step by Step)—3. 自动轮换控制平面 TLS &Webhook TLS 凭证
Linkerd 2.10 系列 快速上手 Linkerd v2 Service Mesh(服务网格) 腾讯云 K8S 集群实战 Service Mesh-Linkerd2 & Traefik2 ...
- kubebuilder实战之六:构建部署运行
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 谈谈redis缓存击穿透和缓存击穿的区别,雪崩效应
面试经历 在很长的一段时间里,我以为缓存击穿和缓存穿透是一个东西,直到最近去腾讯面试,面试官问我缓存击穿和穿透的区别:我回答它俩是一样的,面试官马上抬起头用他那细长的单眼皮眼睛瞪着我说:"你 ...