PHP中比較數組的時候發生了什麼?

  • 2019 年 12 月 4 日
  • 筆記

PHP中比較數組的時候發生了什麼?

首先還是從程式碼來看,我們通過比較運算符號來對兩個數組進行比較:

1var_dump([1, 2] == [2, 1]); // false  2  3var_dump([1, 2, 3] > [3, 2, 1]); // false  4  5var_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 中則數組無法比較,否則挨個值比較

 1<?php   2// 數組用標準比較運算符這樣比較的   3function standard_array_compare($op1, $op2)   4{   5    if (count($op1) < count($op2)) {   6        return -1; // $op1 < $op2   7    } elseif (count($op1) > count($op2)) {   8        return 1; // $op1 > $op2   9    }  10    foreach ($op1 as $key => $val) {  11        if (!array_key_exists($key, $op2)) {  12            return null; // uncomparable  13        } elseif ($val < $op2[$key]) {  14            return -1;  15        } elseif ($val > $op2[$key]) {  16            return 1;  17        }  18    }  19    return 0; // $op1 == $op2  20}

上述程式碼就是php中使用比較操作符進行數組比較時的程式碼,首先是count數組的元素數量,如果數組1大於數組2就返回1,否則返回-1。如果相等的話,遍歷每一個元素進行對比,如果數組1的某個鍵值不存在在數組2中,返回null,如果數組1的某個鍵的值大於數組2的這個鍵的值,返回1,否則返回-1。遍歷的元素也都相同的情況下,最後返回0表示相等。

使用普通的比較操作符對比鍵值對形式的數組效果會好一些,因為是以固定的鍵來進行比對,不是以數組下標:

1var_dump(['a'=>1, 'b'=>2] == ['b'=>2, 'a'=>1]); // ture  2var_dump(['a'=>1, 'b'=>2] == ['a'=>2, 'b'=>1]); // false  3  4  5var_dump(['a' => 1, 'b' => 5] < ['a' => 2, 'b' => 1]); // true

注意第三條比較,我們的第一個數組的b元素是大於第二個數組的,但通過上面的數組比較程式碼可以看出,當第一個元素比較結果已經出現了大於小於的情況時,直接就return返回了結果,後面的元素不會再進行比較了。

那麼多維數組呢?

1var_dump([['aa' => 1], ['bb' => 1, 'dd'=>2]] == [['aa' => 2], ['bb' => 1]]); // false  2var_dump([['aa' => 1], ['bb' => 1, 'dd'=>2]] < [['aa' => 2], ['bb' => 1]]); // true  3var_dump([['aa' => 1], ['bb' => 1, 'dd'=>2]] < [['aa' => 1, 'cc' => 1], ['bb' => 1]]); // true

子數組會遞歸進行比較,比較規則依然是按照默認的數組操作符比較方式進行。

弄清楚了數組的比較是如何進行的,那麼問題來了,假設前端傳給我們的數據是這樣的:

1[  2    'John',  3    '178cm',  4    '62kg',  5]

而我們資料庫里存的是:

1[  2    '62kg',  3    'John',  4    '178cm',  5]

這時如果直接比對兩個數組內容,或者直接用json字元串比對,他們都是不相同的,這可怎麼辦呢?試試自定義一個對比方法吧!

 1function array_equal($a, $b)   2{   3    return (is_array($a) && is_array($b) && array_diff($a, $b) === array_diff($b, $a));   4}   5   6$arr1 = [   7    'John',   8    '178cm',   9    '62kg',  10];  11$arr2 = [  12    '62kg',  13    'John',  14    '178cm',  15];  16  17var_dump(array_equal($arr1, $arr2)); // true  18  19// 元素不一樣的話  20$arr2 = [  21    '62kg',  22    'John Jobs',  23    '178cm',  24];  25var_dump(array_equal($arr1, $arr2)); // false  26  27// 再弄亂一點  28$arr1 = [  29    [  30        '55kg',  31        'Bob',  32        '172cm',  33        [  34            'employee',  35        ],  36    ],  37    [  38        'John',  39        '178cm',  40        '62kg',  41        [  42            'manager',  43        ],  44    ],  45];  46$arr2 = [  47    [  48        '62kg',  49        'John',  50        '178cm',  51        [  52            'manager',  53        ],  54    ],  55    [  56        [  57            'employee',  58        ],  59        '55kg',  60        '172cm',  61        'Bob',  62  63    ],  64];  65var_dump(array_equal($arr1, $arr2)); // true

其實就是利用了array_diff()這個函數,它的作用是取兩個數組的差集,然後再對比兩個數組差集的結果來判斷兩個數組是否相等。這個方法適用於下標數組的比對,但不適用於鍵值對數組的比對,array_diff()只是取值的差集結果集,不會比對鍵,所以對於鍵值對的數組直接使用比較操作符就好啦!

對於數組的比較我們只要弄清楚它的原理就可以了,如果原理不清楚很可能就會埋下隱藏的BUG。數組的比較一定要記住這三點:

1.先比較元素數量

2.再比較每一個元素(多維數組遞歸比較)

3.先後順序,第一個有比較結果了後面就不會繼續比較了,全部都相等才會返回相等

測試程式碼:https://github.com/zhangyue0503/dev-blog/blob/master/php/201910/source/PHP%E4%B8%AD%E6%AF%94%E8%BE%83%E6%95%B0%E7%BB%84%E7%9A%84%E6%97%B6%E5%80%99%E5%8F%91%E7%94%9F%E4%BA%86%E4%BB%80%E4%B9%88%EF%BC%9F.php

參考鏈接:https://www.php.net/manual/zh/language.operators.comparison.php