1. 程式人生 > >PHP 陣列淺析

PHP 陣列淺析

                                                                                      PHP 陣列淺析

一、概要

  • 簡單介紹及基本使用
  • php陣列 常用標準庫函式使用
  • php陣列模擬常見資料結構
  • php陣列使用須知與注意點
  • FAQ

二、簡單介紹及基本使用

  • PHP 中的陣列實際上是一個有序對映。對映是一種把 values 關聯到 keys 的型別。
  • 通過<?php $arr = array(1, 2, 3, 4); 便定義了一個普通陣列
  • 我們還可以定義關聯陣列
$arr = array('a' => 1, 'z' => 100);
  • 如果php版本 >= 5.4 , 我們可以使用更為簡潔的方式定義陣列
$arr = [1, 2, 3, 4];
$arr = ['a' => 1, 'z' => 100];
  • php 陣列很強大, 可以定義混合型別陣列
$arr = [1, 'hello' => '11', 'arr' => [1, 'a'=>'b']];
  • 關於陣列的訪問操作,可以通過[index] 訪問:
$arr = [1, 'hello' => '11', 'arr' => [1, 'a'=>'b']];
var_dump($arr[0]); // 1
var_dump($arr['arr']); // [1, 'a' => 'b']
  • 也可以通過[] 修改陣列元素的值
$arr = [1, 'hello' => '11', 'arr' => [1, 'a'=>'b']];
$arr[0] = 'test';
var_dump($arr); 
  • 你也可以在初始化陣列繼續新增陣列元素
$arr = [1, 2, 3, 4];
$arr[] = 'a';           //追加元素
$arr['test'] = 'b';    // 新增 key, value
  • 當然,刪除陣列元素的操作必須支援
$arr = [1, 'hello' => '11', 'arr' => [1, 'a'=>'b']];
unset($arr['hello']);
var_dump($arr['hello']);  // null
  • 開發中經常需要遍歷陣列, 可使用 foreach :
$arr = [1, 'hello' => '11', 'arr' => [1, 'a'=>'b']];
foreach($arr as $key => $value) {
    var_dump($key . ' => ' . $value);
}

更多陣列遍歷的方法請參考php-陣列遍歷
- 陣列之間的比較,陣列無法比較大小, 但可以根據一定條件判斷是否相等
 

// $a == $b 相等 如果 $a 和 $b 具有相同的鍵/值對則為 TRUE。
// $a === $b 全等 如果 $a 和 $b 具有相同的鍵/值對並且順序和型別都相同則為 TRUE。

$a = [1, 2];
$b = ['1' => 2, 0 => 1];

var_dump($a == $b); // true
var_dump($a === $b); // false

三、實用的陣列工具函式

掌握了陣列的基本操作(定義使用,增刪改查, 遍歷) 之後,你就可以在開發中使用陣列, 但只有這些操作是遠遠不夠的,為了滿足複雜多變的開發場景對陣列操作的需求,PHP 提供了功能強大的一套 Array 操作的函式

  • - 獲取陣列長度
$arr = [1, 2, 3];
var_dump(count($arr)); // 3
  • 希望判斷一個變數是否是陣列,可以通過 is_array():
$arr = [1, 2, 3];
$notArr = '111';
var_dump(is_array($arr)); // true
var_dump(is_array($notArr)); // false
  • 更具key 或者 value, 判斷元素 是否在陣列中
// 判斷key 是否在陣列中
$arr = ['a' => 2, 4];
var_dump(isset($arr['a'])); // true  
var_dump(array_key_exists('a', $arr)); // true

// 判斷 value 是否在陣列中
in_array(5, $arr);  // false
  • 獲取陣列所有鍵(keys)
$arr = ['a' => 2, 4];
$keys = array_keys($arr); // ['a', 1]
  • 獲取陣列的所有值 (values)
$arr = ['a' => 2, 4];
$values = array_values($arr); // [2, 4]
  • 統計陣列各個元素值出現的次數 可以使用 array_count_values:
$arr = [1, 3, 2, 'a' => 1, 'b' => 2];
var_dump(array_count_values($arr));
/* array(3) {
      [1]=>
      int(2)
      [3]=>
      int(1)
      [2]=>
      int(2)
} */

陣列與陣列之間的操作:陣列可以看做一個集合, 集合間的操作(交集,差集,並集, 補集, 比較等) php 也提供相應的方法實現

  • 陣列的合併
$arr1 = ['a' => 1, 2, 'b' => 3];
$arr2 = ['b' => 5, 2];
var_dump( array_merge($arr1, $arr2) );
/* array(4) {
      ["a"]=>
      int(1)
      [0]=>
      int(2)
      ["b"]=>
      int(5)
      [1]=>
      int(2)
    }
// 你也可以使用 + 操作符, 請注意兩種方法結果的差別
var_dump($arr1 + $arr2); */
  • 如果是需要計算兩個或跟多陣列value的交集, 可使用 array_intersect
$arr1 = [1, 2, 3];
$arr2 = [5, 2];
var_dump( array_intersect($arr1, $arr2) );  // [2]
  • 陣列的差集 (按值value 和 按key)
$a = [1, 2];
$b = ['1' => 2, 0 => 1, 4];

//array_diff 按照索引 和 值 比較差異
var_dump(array_diff($a, $b));

// array_diff_key() 函式用於比較兩個(或更多個)陣列的鍵名 ,並返回差集
var_dump(array_diff_key($a, $b));
  • 如果需要獲取子陣列, 可以通過 array_slice 產生類似 python 切片的效果
$arr = [1, 2, 3, 4, 5, 6, 7, 8];
// 從第3個元素開始, 直到結束
var_dump(array_slice($arr, 2));

// 從第3個元素開始, 長度為4
var_dump(array_slice($arr, 2, 4));

// 從第3個元素開始,到倒數第3個元素
var_dump(array_slice($arr, 2, -2));

// 注意 索引的差別
var_dump(array_slice($arr, 2, -2, true));
  • 關於陣列的排序操作,也是比較常見的開發需求,需要注意的是:php排序函式都是直接作用於陣列本身, 而不是返回一個新的有序的陣列。, 以下程式碼提供幾種常見的場景, 更多請參考php對陣列進行排序
    // 按照值(value)升序排序, 索引更新
    $arr = [6,'a'=>2, 3, 4, 6, -1, 7, 8];
    sort($arr);
    var_dump($arr);


    // 按照值(value)升序排序, 索引保持
    $arr = [6,'a'=>2, 3, 4, 6, -1, 7, 8];
    asort($arr);
    var_dump($arr);

    // 按照值(value)降序排序, 索引保持
    $arr = [6,'a'=>2, 3, 4, 6, -1, 7, 8];
    arsort($arr);
    var_dump($arr);

    // 按照 鍵(key)進行升序排序 , 索引保持
    $arr = ['a' => 10, 'c' => 1, 'b' => 12];
    ksort($arr);
    var_dump($arr);


    // 按照 鍵(key)進行降序排序 , 索引保持
    $arr = ['a' => 10, 'c' => 1, 'b' => 12];
    krsort($arr);
    var_dump($arr);

    // 使用者自定義排序, 根據值(value) , 索引更新
    // 請注意:對於自定義的比較函式,
    // 在第一個引數小於,等於或大於第二個引數時,
    // 該比較函式必須相應地返回一個小於,等於或大於 0 的整數。
    function cmp($val1, $val2)
    {
        if($val1 > $val2) {
            return 1;
        } elseif ($val1 == $val2) {
            return 0;
        } else {
            return -1;
        }
    }

    $arr = [
        'a' => 1,
        'A' => 3,
        'B' => 2,
    ];

    usort($arr, cmp);
    var_dump($arr);

    // 根據key 自定義排序規則,請使用 uksort(), 用法同usort()
  • 關於陣列與字串之間的操作一般有切割字串,合併陣列元素轉為字串兩種操作,可以藉助explode與implode實現
    var_dump(explode(',', "a,a,a,a,a,a")); // 以,為分割符將字串"a,a,a,a,a,a" 切割成陣列

    var_dump(implode('-', [1, 2, 3, 4, 5])); //以 - 為 拼接符 將 陣列[1, 2, 3, 4, 5] 拼接成字串

關於php 更多陣列相關的函式, 可以參考 官方文件php陣列函式列表

四、陣列模擬常見資料結構

php 陣列可以模擬常見的資料結構,最顯而易見的便是 對映表 和 字典, 這裡簡單介紹php陣列對棧和佇列的模擬。

  • 模擬棧(FILO)
    $stack = [1, 2, 3, 4];

    //入棧
    array_push($stack, -1);
    var_dump($stack); // [1, 2, 3, 4, -1]

    //出棧
    $e = array_pop($stack);
    var_dump($e); // -1
    var_dump($stack);  // [1, 2, 3, 4]
  • 模擬佇列 (FIFO)
    $queue = [];

    //入佇列
    array_unshift($queue, 1);
    array_unshift($queue, 2);
    array_unshift($queue, 3);
    array_unshift($queue, 4);

    //出佇列
    $e = array_pop($queue);
    var_dump($e); // 1
    $e = array_pop($queue);
    var_dump($e); // 2
    $e = array_pop($queue);
    var_dump($e); // 3
    $e = array_pop($queue);
    var_dump($e); // 4

五、php陣列使用須知與注意點

  • php 陣列 key值 會存在以下強制轉換
    • 包含有合法整型值的字串會被轉換為整型。例如鍵名 “8” 實際會被儲存為 8。但是 “08” 則不會強制轉換,因為其不是一個合法的十進位制數值。
    • 浮點數也會被轉換為整型,意味著其小數部分會被捨去。例如鍵名 8.7 實際會被儲存為 8。
    • 布林值也會被轉換成整型。即鍵名 true 實際會被儲存為 1 而鍵名 false 會被儲存為 0。
    • Null 會被轉換為空字串,即鍵名 null 實際會被儲存為 “”。
    • 陣列和物件不能被用為鍵名。堅持這麼做會導致警告:Illegal offset type。

因此以下程式碼可能導致意外的結果,請注意以下程式碼的輸出

    $arr = [1, 2, '8' => 3];

    $arr[false] = -20;
    var_dump($arr); // [-20, 2, '8' => 3]

    $arr[8] = 20;
    var_dump($arr); // [-20, 2, 8 => 20]

    $arr[8.7] = 15;
    var_dump($arr); // [-20, 2, 8 => 15]

    $arr["8.7"] = 10;
    var_dump($arr); // [-20, 2, 8 => 10]


    $arr[$val]  = 5; // 注意$val之前為宣告,因此預設值為null, 陣列key為null時會被轉為""空串
    var_dump($arr); // [-20, 2, 8 => 10, "" => 5]

    $arr[bar] = 6; // 識別符號被轉化為 'bar'
    var_dump($arr); // [-20, 2, 8 => 10, "" => 5, 'bar' => 6]
  • 關於php陣列的型別轉換

php陣列可以將其他一切型別轉為陣列,轉化的效果請參考一下程式碼,重點觀察對 null 和 object物件的轉化:

    $var = true;
    var_dump((array)$var);
    /* array(1) {
      [0]=>
      bool(true)
    }*/

    $var = 1;
    var_dump((array)$var);
    /* array(1) {
      [0]=>
      int(1)
    }*/

    $var = 1.1;
    var_dump((array)$var);
    /* array(1) {
      [0]=>
      float(1.1)
    }*/

    $var = "111";
    var_dump((array)$var);
    /* array(1) {
      [0]=>
      string(3) "111"
    }*/

    $var = null;
    var_dump((array)$var);  // 返回空陣列
    /* array(0) {
    } */

    class Cls { public $a = 1; protected $b = 2; private $c = 3; }
    var_dump((array)(new Cls)); // 可見性不同 key值格式有所不同
    /* array(3) {
      ["a"]=>
      int(1)
      ["*b"]=>
      int(2)
      ["Clsc"]=>
      int(3)
    } */

關於PHP型別轉換的瞭解,請參考PHP-型別轉換的判別

六、FAQ

  • 如何新增陣列元素更為高效? array_push($arr, key, value) or $arr[key] = value ?

    答: 後者更為高效, 更多細節請參考官方資料

  • isset or array_key_exists() ?

    答:

  • 對於存在key的陣列,如果 對應的value = null , isset($arr[key]) 會返回 false;而對於array_key_exists 只要對應key存在就會返回true;
  • 然而在效率方面,isset 效率 高於array_key_eixsts
    在判斷陣列元素是否存在的最佳實踐如下: 

                if (isset($arr[$key]) or array_key_exists($key, $arr)) {
                  ...
               }

  • 數組合並 +array_merge 的區別?

        答:可以參考該資料

  • array_diff == 的異同?

        答:語義有所差別, 陣列的相等比較 推薦只使用 ==

  • 遍歷方式那種更高效?

       答:foreach 方式 遍歷 最為高效

 

轉載地址:PHP 陣列淺析