ArrayHelper
В дополнение к широкому набору функций PHP для работы с массивами, помощник Yii для массивов предоставляет дополнительные статические методы, позволяющие более эффективно работать с массивами.
Получение значений
Извлечение значений из массива, объекта или сложной структуры, состоящей из обоих, с использованием стандартных функций 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');
Если вам нужно получить значение и сразу же удалить его из массива, вы можете использовать метод 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.";
}
Извлечение столбцов
Часто вам нужно получить столбец значений из массива строк данных или объектов. Типичный пример — получение списка идентификаторов.
$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 в качестве третьего аргумента сгруппирует $array по id:
$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) {
return isset($item['age']) ? ['age', 'name'] : 'name';
});
Третий аргумент — направление. В случае сортировки по одному ключу он может быть либо SORT_ASC, либо SORT_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',
],
]
Преобразование объектов в массивы
Часто вам нужно преобразовать объект или массив объектов в массив. Наиболее распространенный случай — преобразование моделей активных записей для предоставления массивов данных через API REST или для другого использования. Следующий код может быть использован для этого:
$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']));
© 2008–2017 by Yii Software LLC
Licensed under the three clause BSD license.
http://www.yiiframework.com/doc-2.0/guide-helper-array.html