helper-array.md 9.09 KB
Newer Older
1 2 3 4 5
ArrayHelper
===========

Additionally to [rich set of PHP array functions](http://php.net/manual/en/book.array.php) Yii array helper provides
extra static methods allowing you to deal with arrays more efficiently.
6

7

8
## Getting Values <span id="getting-values"></span>
9 10

Retrieving values from an array, an object or a complex structure consisting of both using standard PHP is quite
11
repetitive. You have to check if key exists with `isset` first, then if it does you're getting it, if not,
12
providing default value:
13

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
```php
class User
{
    public $name = 'Alex';
}

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

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

Yii provides a very convenient method to do it:

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

First method argument is where we're getting value from. Second argument specifies how to get the data. It could be one
of the following:
37

38
- Name of array key or object property to retrieve value from.
39
- Set of dot separated array keys or object property names. The one we've used in the example above.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
- A callback returning a value.

The callback should be the following:

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

Third optional argument is default value which is `null` if not specified. Could be used as follows:

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

In case you want to get the value and then immediately remove it from array you can use `remove` method:
57

58 59 60 61 62 63 64 65 66
```php
$array = ['type' => 'A', 'options' => [1, 2]];
$type = ArrayHelper::remove($array, 'type');
```

After executing the code `$array` will contain `['options' => [1, 2]]` and `$type` will be `A`. Note that unlike
`getValue` method, `remove` supports simple key names only.


67
## Checking Existence of Keys <span id="checking-existence-of-keys"></span>
68 69

`ArrayHelper::keyExists` works the same way as [array_key_exists](http://php.net/manual/en/function.array-key-exists.php)
Qiang Xue committed
70
except that it also supports case-insensitive key comparison. For example,
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

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

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

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

86
## Retrieving Columns <span id="retrieving-columns"></span>
87

88
Often you need to get a column of values from array of data rows or objects. Common example is getting a list of IDs.
89 90 91 92 93 94 95 96 97 98

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

The result will be `['123', '345']`.
99

100 101 102 103 104 105 106 107
If additional transformations are required or the way of getting value is complex, second argument could be specified
as an anonymous function:

```php
$result = ArrayHelper::getColumn($array, function ($element) {
    return $element['id'];
});
```
Qiang Xue committed
108

109

110
## Re-indexing Arrays <span id="reindexing-arrays"></span>
111

112
In order to index an array according to a specified key, the `index` method can be used. The input array should be
113 114 115 116
multidimensional or an array of objects. The key can be a key name of the sub-array, a property name of object, or
an anonymous function which returns the key value given an array element.

If a key value is null, the corresponding array element will be discarded and not put in the result. For example,
117

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
```php
$array = [
    ['id' => '123', 'data' => 'abc'],
    ['id' => '345', 'data' => 'def'],
];
$result = ArrayHelper::index($array, 'id');
// the result is:
// [
//     '123' => ['id' => '123', 'data' => 'abc'],
//     '345' => ['id' => '345', 'data' => 'def'],
// ]

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

136

137
## Building Maps <span id="building-maps"></span>
138 139 140 141

In order to build a map (key-value pairs) from a multidimensional array or an array of objects you can use `map` method.
The `$from` and `$to` parameters specify the key names or property names to set up the map. Optionally, one can further
group the map according to a grouping field `$group`. For example,
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
```php
$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',
//     ],
// ]
```
170 171


172
## Multidimensional Sorting <span id="multidimensional-sorting"></span>
173

174
`multisort` method helps to sort an array of objects or nested arrays by one or several keys. For example,
175 176 177 178 179 180 181

```php
$data = [
    ['age' => 30, 'name' => 'Alexander'],
    ['age' => 30, 'name' => 'Brian'],
    ['age' => 19, 'name' => 'Barney'],
];
182
ArrayHelper::multisort($data, ['age', 'name'], [SORT_ASC, SORT_DESC]);
183 184 185 186 187 188 189 190 191 192 193 194
```

After sorting we'll get the following in `$data`:

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

195
Second argument that specifies keys to sort by can be a string if it's a single key, an array in case of multiple keys
196 197 198 199 200 201 202
or an anonymous function like the following one:

```php
ArrayHelper::multisort($data, function($item) {
    return isset($item['age']) ? ['age', 'name'] : 'name';
});
```
203

204 205
Third argument is direction. In case of sorting by a single key it could be either `SORT_ASC` or
`SORT_DESC`. If sorting by multiple values you can sort each value differently by providing an array of
206 207 208 209
sort direction.

Last argument is PHP sort flag that could take the same values as the ones passed to
PHP [sort()](http://php.net/manual/en/function.sort.php).
210

Qiang Xue committed
211

212
## Detecting Array Types <span id="detecting-array-types"></span>
213

214
It is handy to know whether an array is indexed or an associative. Here's an example:
215

216 217 218 219 220 221 222 223 224
```php
// no keys specified
$indexed = ['Qiang', 'Paul'];
echo ArrayHelper::isIndexed($indexed);

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

Qiang Xue committed
226

227
## HTML Encoding and Decoding Values <span id="html-encoding-values"></span>
228 229 230 231 232 233 234 235

In order to encode or decode special characters in an array of strings into HTML entities you can use the following:

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

236
Only values will be encoded by default. By passing second argument as `false` you can encode array's keys as well.
237
Encoding will use application charset and could be changed via third argument.
238 239


240
## Merging Arrays <span id="merging-arrays"></span>
241

242
```php
243
  /**
244 245 246 247 248 249 250 251 252 253 254 255
    * Merges two or more arrays into one recursively.
    * If each array has an element with the same string key value, the latter
    * will overwrite the former (different from array_merge_recursive).
    * Recursive merging will be conducted if both arrays have an element of array
    * type and are having the same key.
    * For integer-keyed elements, the elements from the latter array will
    * be appended to the former array.
    * @param array $a array to be merged to
    * @param array $b array to be merged from. You can specify additional
    * arrays via third argument, fourth argument etc.
    * @return array the merged array (the original arrays are not changed.)
    */
256
    public static function merge($a, $b)
257 258 259
```


260
## Converting Objects to Arrays <span id="converting-objects-to-arrays"></span>
261

262
Often you need to convert an object or an array of objects into an array. The most common case is converting active record
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
models in order to serve data arrays via REST API or use it otherwise. The following code could be used to do it:

```php
$posts = Post::find()->limit(10)->all();
$data = ArrayHelper::toArray($post, [
    '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);
        },
    ],
]);
```

281
The first argument contains the data we want to convert. In our case we're converting a `Post` AR model.
282

283
The second argument is conversion mapping per class. We're setting a mapping for `Post` model.
284
Each mapping array contains a set of mappings. Each mapping could be:
285

286
- A field name to include as is.
287 288
- A key-value pair of desired array key name and model column name to take value from.
- A key-value pair of desired array key name and a callback which returns value.
289 290

The result of conversion above will be:
291 292


293 294 295 296 297 298 299 300 301 302
```php
[
    'id' => 123,
    'title' => 'test',
    'createTime' => '2013-01-01 12:00AM',
    'length' => 301,
]
```

It is possible to provide default way of converting object to array for a specific class by implementing
Qiang Xue committed
303
[[yii\base\Arrayable|Arrayable]] interface in that class.