3 追蹤者

ArrayHelper

除了 豐富的 PHP 陣列函式集 之外,Yii 陣列 helper 還提供了額外的靜態方法,讓您可以更有效率地處理陣列。

取得數值

從陣列、物件或由兩者組成的複雜結構中檢索數值,使用標準 PHP 是相當重複乏味的。您必須先使用 isset 檢查鍵是否存在,如果存在則取得它,否則提供預設值。

class User
{
    public $name = 'Alex';
}

$array = [
    'foo' => [
        'bar' => new User(),
    ]
];

$value = isset($array['foo']['bar']->name) ? $array['foo']['bar']->name : null;

Yii 提供了一個非常方便的方法來做到這一點。

$value = ArrayHelper::getValue($array, 'foo.bar.name');

第一個方法參數是我們要從哪裡取得數值。第二個參數指定如何取得資料。它可以是以下其中之一:

  • 要從中檢索數值的陣列鍵名或物件屬性名稱。
  • 一組點分隔的陣列鍵或物件屬性名稱。就是我們在上面範例中使用的那一個。
  • 傳回數值的回呼。

回呼應如下:

$fullName = ArrayHelper::getValue($user, function ($user, $defaultValue) {
    return $user->firstName . ' ' . $user->lastName;
});

第三個可選參數是預設值,如果未指定,則為 null。可以如下使用:

$username = ArrayHelper::getValue($comment, 'user.username', 'Unknown');

設定數值

$array = [
    'key' => [
        'in' => ['k' => 'value']
    ]
];

ArrayHelper::setValue($array, 'key.in', ['arr' => 'val']);
// the path to write the value in `$array` can be specified as an array
ArrayHelper::setValue($array, ['key', 'in'], ['arr' => 'val']);

結果,$array['key']['in'] 的初始值將被新值覆寫。

[
    'key' => [
        'in' => ['arr' => 'val']
    ]
]

如果路徑包含不存在的鍵,它將被建立。

// if `$array['key']['in']['arr0']` is not empty, the value will be added to the array
ArrayHelper::setValue($array, 'key.in.arr0.arr1', 'val');

// if you want to completely override the value `$array['key']['in']['arr0']`
ArrayHelper::setValue($array, 'key.in.arr0', ['arr1' => 'val']);

結果將是:

[
    'key' => [
        'in' => [
            'k' => 'value',
            'arr0' => ['arr1' => 'val']
        ]
    ]
]

從陣列中取出數值

如果您想要取得一個數值,然後立即從陣列中移除它,您可以使用 remove 方法。

$array = ['type' => 'A', 'options' => [1, 2]];
$type = ArrayHelper::remove($array, 'type');

執行程式碼後,$array 將包含 ['options' => [1, 2]],而 $type 將為 A。請注意,與 getValue 方法不同,remove 僅支援簡單的鍵名。

檢查鍵是否存在

ArrayHelper::keyExists 的運作方式與 array_key_exists 相同,只是它也支援不區分大小寫的鍵比較。例如:

$data1 = [
    'userName' => 'Alex',
];

$data2 = [
    'username' => 'Carsten',
];

if (!ArrayHelper::keyExists('username', $data1, false) || !ArrayHelper::keyExists('username', $data2, false)) {
    echo "Please provide username.";
}

取得欄位

通常您需要從資料列或物件陣列中取得數值欄位。常見的範例是取得 ID 列表。

$array = [
    ['id' => '123', 'data' => 'abc'],
    ['id' => '345', 'data' => 'def'],
];
$ids = ArrayHelper::getColumn($array, 'id');

結果將會是 ['123', '345']

如果需要額外的轉換,或者取得數值的方式很複雜,則第二個參數可以指定為匿名函式。

$result = ArrayHelper::getColumn($array, function ($element) {
    return $element['id'];
});

重新索引陣列

為了根據指定的鍵索引陣列,可以使用 index 方法。輸入應該是多維陣列或物件陣列。$key 可以是子陣列的鍵名、物件的屬性名稱,或必須傳回將用作鍵的值的匿名函式。

$groups 屬性是一個鍵陣列,將用於根據指定的鍵將輸入陣列分組為一個或多個子陣列。

如果特定元素的 $key 屬性或其值為 null 且未定義 $groups,則將捨棄陣列元素。否則,如果指定了 $groups,則陣列元素將被添加到結果陣列中,而沒有任何鍵。

例如:

$array = [
    ['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
    ['id' => '345', 'data' => 'def', 'device' => 'tablet'],
    ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
];
$result = ArrayHelper::index($array, 'id');

結果將是一個關聯陣列,其中鍵是 id 屬性的值。

[
    '123' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
    '345' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
    // The second element of an original array is overwritten by the last element because of the same id
]

作為 $key 傳遞的匿名函式,會產生相同的結果。

$result = ArrayHelper::index($array, function ($element) {
    return $element['id'];
});

id 作為第三個參數傳遞,將會依 id 分組 $array

$result = ArrayHelper::index($array, null, 'id');

結果將是一個多維陣列,在第一層依 id 分組,在第二層未索引。

[
    '123' => [
        ['id' => '123', 'data' => 'abc', 'device' => 'laptop']
    ],
    '345' => [ // all elements with this index are present in the result array
        ['id' => '345', 'data' => 'def', 'device' => 'tablet'],
        ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
    ]
]

匿名函式也可以在分組陣列中使用。

$result = ArrayHelper::index($array, 'data', [function ($element) {
    return $element['id'];
}, 'device']);

結果將是一個多維陣列,在第一層依 id 分組,在第二層依 device 分組,在第三層依 data 索引。

[
    '123' => [
        'laptop' => [
            'abc' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop']
        ]
    ],
    '345' => [
        'tablet' => [
            'def' => ['id' => '345', 'data' => 'def', 'device' => 'tablet']
        ],
        'smartphone' => [
            'hgi' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
        ]
    ]
]

建立地圖

為了從多維陣列或物件陣列建立地圖(鍵值對),您可以使用 map 方法。$from$to 參數指定設定地圖的鍵名或屬性名稱。可選地,可以根據分組欄位 $group 進一步分組地圖。例如:

$array = [
    ['id' => '123', 'name' => 'aaa', 'class' => 'x'],
    ['id' => '124', 'name' => 'bbb', 'class' => 'x'],
    ['id' => '345', 'name' => 'ccc', 'class' => 'y'],
];

$result = ArrayHelper::map($array, 'id', 'name');
// the result is:
// [
//     '123' => 'aaa',
//     '124' => 'bbb',
//     '345' => 'ccc',
// ]

$result = ArrayHelper::map($array, 'id', 'name', 'class');
// the result is:
// [
//     'x' => [
//         '123' => 'aaa',
//         '124' => 'bbb',
//     ],
//     'y' => [
//         '345' => 'ccc',
//     ],
// ]

多維排序

multisort 方法有助於依一個或多個鍵排序物件陣列或巢狀陣列。例如:

$data = [
    ['age' => 30, 'name' => 'Alexander'],
    ['age' => 30, 'name' => 'Brian'],
    ['age' => 19, 'name' => 'Barney'],
];
ArrayHelper::multisort($data, ['age', 'name'], [SORT_ASC, SORT_DESC]);

排序後,我們將在 $data 中得到以下內容:

[
    ['age' => 19, 'name' => 'Barney'],
    ['age' => 30, 'name' => 'Brian'],
    ['age' => 30, 'name' => 'Alexander'],
];

指定要排序的鍵的第二個參數可以是字串(如果它是單個鍵)、陣列(如果是多個鍵)或匿名函式,如下所示:

ArrayHelper::multisort($data, function($item) {
    // sort by age if it exists or by name otherwise
    return isset($item['age']) ? $item['age'] : $item['name'];
});

第三個參數是方向。在依單個鍵排序的情況下,它可以是 SORT_ASCSORT_DESC。如果依多個值排序,您可以透過提供排序方向陣列來不同地排序每個值。

最後一個參數是 PHP 排序標誌,它可以採用與傳遞給 PHP sort() 相同的值。

偵測陣列類型

知道陣列是索引陣列還是關聯陣列很方便。以下是一個範例:

// no keys specified
$indexed = ['Qiang', 'Paul'];
echo ArrayHelper::isIndexed($indexed);

// all keys are strings
$associative = ['framework' => 'Yii', 'version' => '2.0'];
echo ArrayHelper::isAssociative($associative);

HTML 編碼與解碼數值

為了將字串陣列中的特殊字元編碼或解碼為 HTML 實體,您可以使用以下方法:

$encoded = ArrayHelper::htmlEncode($data);
$decoded = ArrayHelper::htmlDecode($data);

預設情況下,只會編碼數值。透過將第二個參數作為 false 傳遞,您也可以編碼陣列的鍵。編碼將使用應用程式字元集,並且可以透過第三個參數變更。

合併陣列

您可以使用 ArrayHelper::merge() 將兩個或多個陣列遞迴地合併為一個。如果每個陣列都有一個具有相同字串鍵值的元素,則後者將覆寫前者(與 array_merge_recursive() 不同)。如果兩個陣列都有陣列類型的元素且具有相同的鍵,則將執行遞迴合併。對於整數索引的元素,後一個陣列中的元素將附加到前一個陣列。您可以使用 yii\helpers\UnsetArrayValue 物件從先前的陣列中取消設定值,或使用 yii\helpers\ReplaceArrayValue 強制取代先前的值而不是遞迴合併。

例如:

$array1 = [
    'name' => 'Yii',
    'version' => '1.1',
    'ids' => [
        1,
    ],
    'validDomains' => [
        'example.com',
        'www.example.com',
    ],
    'emails' => [
        'admin' => 'admin@example.com',
        'dev' => 'dev@example.com',
    ],
];

$array2 = [
    'version' => '2.0',
    'ids' => [
        2,
    ],
    'validDomains' => new \yii\helpers\ReplaceArrayValue([
        'yiiframework.com',
        'www.yiiframework.com',
    ]),
    'emails' => [
        'dev' => new \yii\helpers\UnsetArrayValue(),
    ],
];

$result = ArrayHelper::merge($array1, $array2);

結果將是:

[
    'name' => 'Yii',
    'version' => '2.0',
    'ids' => [
        1,
        2,
    ],
    'validDomains' => [
        'yiiframework.com',
        'www.yiiframework.com',
    ],
    'emails' => [
        'admin' => 'admin@example.com',
    ],
]

將物件轉換為陣列

通常您需要將物件或物件陣列轉換為陣列。最常見的情況是轉換 active record 模型,以便透過 REST API 提供資料陣列或以其他方式使用它。可以使用以下程式碼來完成此操作:

$posts = Post::find()->limit(10)->all();
$data = ArrayHelper::toArray($posts, [
    'app\models\Post' => [
        'id',
        'title',
        // the key name in array result => property name
        'createTime' => 'created_at',
        // the key name in array result => anonymous function
        'length' => function ($post) {
            return strlen($post->content);
        },
    ],
]);

第一個參數包含我們要轉換的資料。在我們的範例中,我們正在轉換 Post AR 模型。

第二個參數是每個類別的轉換對應。我們正在為 Post 模型設定對應。每個對應陣列都包含一組對應。每個對應可以是:

  • 要按原樣包含的欄位名稱。
  • 所需陣列鍵名和要從中取得值的模型欄位名稱的鍵值對。
  • 所需陣列鍵名和傳回值的回呼的鍵值對。

上面單個模型的轉換結果將是:

[
    'id' => 123,
    'title' => 'test',
    'createTime' => '2013-01-01 12:00AM',
    'length' => 301,
]

可以透過在該類別中實作 Arrayable 介面,為特定類別提供將物件轉換為陣列的預設方式。

針對陣列進行測試

通常您需要檢查元素是否在陣列中,或一組元素是否是另一個元素的子集。雖然 PHP 提供了 in_array(),但它不支援子集或 \Traversable 物件。

為了幫助進行這些種類的測試,yii\helpers\ArrayHelper 提供了 isIn()isSubset(),它們的簽名與 in_array() 相同。

// true
ArrayHelper::isIn('a', ['a']);
// true
ArrayHelper::isIn('a', new ArrayObject(['a']));

// true 
ArrayHelper::isSubset(new ArrayObject(['a', 'c']), new ArrayObject(['a', 'b', 'c']));

發現錯字或您認為此頁面需要改進?
在 github 上編輯它 !