1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Defines the \TraderInteractive\Util\Arrays class. |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace TraderInteractive\Util; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Class of static array utility functions. |
10
|
|
|
*/ |
11
|
|
|
final class Arrays |
12
|
|
|
{ |
13
|
|
|
/** |
14
|
|
|
* Const for lower cased array keys. |
15
|
|
|
* |
16
|
|
|
* @const integer |
17
|
|
|
*/ |
18
|
|
|
const CASE_LOWER = 1; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Const for upper cased array keys. |
22
|
|
|
* |
23
|
|
|
* @const integer |
24
|
|
|
*/ |
25
|
|
|
const CASE_UPPER = 2; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Const for camel caps cased array keys. |
29
|
|
|
* |
30
|
|
|
* @const integer |
31
|
|
|
*/ |
32
|
|
|
const CASE_CAMEL_CAPS = 4; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Const for underscored cased array keys. |
36
|
|
|
* |
37
|
|
|
* @const integer |
38
|
|
|
*/ |
39
|
|
|
const CASE_UNDERSCORE = 8; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Simply returns an array value if the key exist or null if it does not. |
43
|
|
|
* |
44
|
|
|
* @param array $array the array to be searched |
45
|
|
|
* @param string|integer $key the key to search for |
46
|
|
|
* @param mixed $default the value to return if the $key is not found in $array |
47
|
|
|
* |
48
|
|
|
* @return mixed array value or given default value |
49
|
|
|
*/ |
50
|
|
|
public static function get(array $array, $key, $default = null) |
51
|
|
|
{ |
52
|
|
|
return array_key_exists($key, $array) ? $array[$key] : $default; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Simply returns an array value if the key isset,4 $default if it is not |
57
|
|
|
* |
58
|
|
|
* @param array $array the array to be searched |
59
|
|
|
* @param string|integer $key the key to search for |
60
|
|
|
* @param mixed $default the value to return if the $key is not found in $array or if the value of $key element is |
61
|
|
|
* null |
62
|
|
|
* |
63
|
|
|
* @return mixed array value or given default value |
64
|
|
|
*/ |
65
|
|
|
public static function getIfSet(array $array, $key, $default = null) |
66
|
|
|
{ |
67
|
|
|
return isset($array[$key]) ? $array[$key] : $default; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Sets destination array values to be the source values if the source key exist in the source array. |
72
|
|
|
* |
73
|
|
|
* @param array $source |
74
|
|
|
* @param array &$dest |
75
|
|
|
* @param array $keyMap mapping of dest keys to source keys. If $keyMap is associative, the keys will be the |
76
|
|
|
* destination keys. If numeric the values will be the destination keys |
77
|
|
|
* |
78
|
|
|
* @return void |
79
|
|
|
*/ |
80
|
|
View Code Duplication |
public static function copyIfKeysExist(array $source, array &$dest, array $keyMap) |
|
|
|
|
81
|
|
|
{ |
82
|
|
|
foreach ($keyMap as $destKey => $sourceKey) { |
83
|
|
|
if (is_int($destKey)) { |
84
|
|
|
$destKey = $sourceKey; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
if (array_key_exists($sourceKey, $source)) { |
88
|
|
|
$dest[$destKey] = $source[$sourceKey]; |
89
|
|
|
} |
90
|
|
|
} |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Sets destination array values to be the source values if the source key is set in the source array. |
95
|
|
|
* |
96
|
|
|
* @param array $source |
97
|
|
|
* @param array &$dest |
98
|
|
|
* @param array $keyMap mapping of dest keys to source keys. If $keyMap is associative, the keys will be the |
99
|
|
|
* destination keys. If numeric the values will be the destination keys |
100
|
|
|
* |
101
|
|
|
* @return void |
102
|
|
|
*/ |
103
|
|
View Code Duplication |
public static function copyIfSet(array $source, array &$dest, array $keyMap) |
|
|
|
|
104
|
|
|
{ |
105
|
|
|
foreach ($keyMap as $destKey => $sourceKey) { |
106
|
|
|
if (is_int($destKey)) { |
107
|
|
|
$destKey = $sourceKey; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
if (isset($source[$sourceKey])) { |
111
|
|
|
$dest[$destKey] = $source[$sourceKey]; |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Returns true and fills $value if $key exists in $array, otherwise fills $value with null and returns false |
118
|
|
|
* |
119
|
|
|
* @param array $array The array to pull from |
120
|
|
|
* @param string|integer $key The key to get |
121
|
|
|
* @param mixed &$value The value to set |
122
|
|
|
* |
123
|
|
|
* @return bool true if $key was found and filled in $value, false if $key was not found and $value was set to null |
124
|
|
|
*/ |
125
|
|
|
public static function tryGet(array $array, $key, &$value) : bool |
126
|
|
|
{ |
127
|
|
|
if ((is_string($key) || is_int($key)) && array_key_exists($key, $array)) { |
128
|
|
|
$value = $array[$key]; |
129
|
|
|
return true; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
$value = null; |
133
|
|
|
return false; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Projects values of a key into an array. |
138
|
|
|
* |
139
|
|
|
* if $input = [ |
140
|
|
|
* ['key 1' => 'item 1 value 1', 'key 2' => 'item 1 value 2'], |
141
|
|
|
* ['key 1' => 'item 2 value 1', 'key 2' => 'item 2 value 2'], |
142
|
|
|
* ['key 1' => 'item 3 value 1'], |
143
|
|
|
* ] |
144
|
|
|
* and $key = 'key 2' |
145
|
|
|
* and $strictKeyCheck = false |
146
|
|
|
* |
147
|
|
|
* then return ['item 1 value 2', 'item 2 value 2'] |
148
|
|
|
* |
149
|
|
|
* but if $strictKeyCheck = true then an InvalidArgumentException occurs since 'key 2' wasnt in item 3 |
150
|
|
|
* |
151
|
|
|
* @param array $input the array to project from |
152
|
|
|
* @param string|integer $key the key which values we are to project |
153
|
|
|
* @param boolean $strictKeyCheck ensure key is in each $input array or not |
154
|
|
|
* |
155
|
|
|
* @return array the projection |
156
|
|
|
* |
157
|
|
|
* @throws \InvalidArgumentException if a value in $input was not an array |
158
|
|
|
* @throws \InvalidArgumentException if a key was not in one of the $input arrays |
159
|
|
|
*/ |
160
|
|
|
public static function project(array $input, $key, bool $strictKeyCheck = true) : array |
161
|
|
|
{ |
162
|
|
|
$projection = []; |
163
|
|
|
|
164
|
|
|
foreach ($input as $itemKey => $item) { |
165
|
|
|
self::ensureIsArray($item, 'a value in $input was not an array'); |
166
|
|
|
|
167
|
|
|
if (array_key_exists($key, $item)) { |
168
|
|
|
$projection[$itemKey] = $item[$key]; |
169
|
|
|
} elseif ($strictKeyCheck) { |
170
|
|
|
throw new \InvalidArgumentException('key was not in one of the $input arrays'); |
171
|
|
|
} |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
return $projection; |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Returns a sub set of the given $array based on the given $conditions |
179
|
|
|
* |
180
|
|
|
* @param array[] $array an array of arrays to be checked |
181
|
|
|
* @param array $conditions array of key/value pairs to filter by |
182
|
|
|
* |
183
|
|
|
* @return array the subset |
184
|
|
|
* |
185
|
|
|
* @throws \InvalidArgumentException if a value in $array was not an array |
186
|
|
|
*/ |
187
|
|
|
public static function where(array $array, array $conditions) : array |
188
|
|
|
{ |
189
|
|
|
$result = []; |
190
|
|
|
foreach ($array as $item) { |
191
|
|
|
self::ensureIsArray($item, 'a value in $array was not an array'); |
192
|
|
|
|
193
|
|
|
foreach ($conditions as $key => $value) { |
194
|
|
|
if (!array_key_exists($key, $item) || $item[$key] !== $value) { |
195
|
|
|
continue 2; // continue to the next item in $array |
196
|
|
|
} |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
$result[] = $item; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
return $result; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Takes each item and embeds it into the destination array, returning the result. |
207
|
|
|
* |
208
|
|
|
* Each item's key is used as the key in the destination array so that keys are preserved. Each resulting item in |
209
|
|
|
* the destination will be embedded into a field named by $fieldName. Any items that don't have an entry in |
210
|
|
|
* destination already will be added, not skipped. |
211
|
|
|
* |
212
|
|
|
* For example, embedInto(['Joe', 'Sue'], 'lastName', [['firstName' => 'Billy'], ['firstName' => 'Bobby']]) will |
213
|
|
|
* return [['firstName' => 'Billy', 'lastName' => 'Joe'], ['firstName' => 'Bobby', 'lastName' => 'Sue']] |
214
|
|
|
* |
215
|
|
|
* @param array $items The items to embed into the result. |
216
|
|
|
* @param string $fieldName The name of the field to embed the items into. This field must not exist in the |
217
|
|
|
* destination items already. |
218
|
|
|
* @param array $destination An optional array of arrays to embed the items into. If this is not provided then |
219
|
|
|
* empty records are assumed and the new record will be created only containing |
220
|
|
|
* $fieldName. |
221
|
|
|
* @param bool $overwrite whether to overwrite $fieldName in $destination array |
222
|
|
|
* |
223
|
|
|
* @return array $destination, with all items in $items added using their keys, but underneath a nested $fieldName |
224
|
|
|
* key. |
225
|
|
|
* |
226
|
|
|
* @throws \InvalidArgumentException if $fieldName was not a string |
227
|
|
|
* @throws \InvalidArgumentException if a value in $destination was not an array |
228
|
|
|
* @throws \Exception if $fieldName key already exists in a $destination array |
229
|
|
|
*/ |
230
|
|
|
public static function embedInto( |
231
|
|
|
array $items, |
232
|
|
|
string $fieldName, |
233
|
|
|
array $destination = [], |
234
|
|
|
bool $overwrite = false |
235
|
|
|
) : array { |
236
|
|
|
foreach ($items as $key => $item) { |
237
|
|
|
if (!array_key_exists($key, $destination)) { |
238
|
|
|
$destination[$key] = [$fieldName => $item]; |
239
|
|
|
continue; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
self::ensureIsArray($destination[$key], 'a value in $destination was not an array'); |
243
|
|
|
|
244
|
|
|
if (!$overwrite && array_key_exists($fieldName, $destination[$key])) { |
245
|
|
|
throw new \Exception('$fieldName key already exists in a $destination array'); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
$destination[$key][$fieldName] = $item; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
return $destination; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Fills the given $template array with values from the $source array |
256
|
|
|
* |
257
|
|
|
* @param array $template the array to be filled |
258
|
|
|
* @param array $source the array to fetch values from |
259
|
|
|
* |
260
|
|
|
* @return array Returns a filled version of $template |
261
|
|
|
*/ |
262
|
|
|
public static function fillIfKeysExist(array $template, array $source) |
263
|
|
|
{ |
264
|
|
|
$result = $template; |
265
|
|
|
foreach ($template as $key => $value) { |
266
|
|
|
if (array_key_exists($key, $source)) { |
267
|
|
|
$result[$key] = $source[$key]; |
268
|
|
|
} |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
return $result; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* Extracts an associative array from the given multi-dimensional array. |
276
|
|
|
* |
277
|
|
|
* @param array $input The multi-dimensional array. |
278
|
|
|
* @param string|int $keyIndex The index to be used as the key of the resulting single dimensional result array. |
279
|
|
|
* @param string|int $valueIndex The index to be used as the value of the resulting single dimensional result array. |
280
|
|
|
* If a sub array does not contain this element null will be used as the value. |
281
|
|
|
* @param string $duplicateBehavior Instruct how to handle duplicate resulting values, 'takeFirst', 'takeLast', |
282
|
|
|
* 'throw' |
283
|
|
|
* |
284
|
|
|
* @return array an associative array |
285
|
|
|
* |
286
|
|
|
* @throws \InvalidArgumentException Thrown if $input is not an multi-dimensional array |
287
|
|
|
* @throws \InvalidArgumentException Thrown if $keyIndex is not an int or string |
288
|
|
|
* @throws \InvalidArgumentException Thrown if $valueIndex is not an int or string |
289
|
|
|
* @throws \InvalidArgumentException Thrown if $duplicateBehavior is not 'takeFirst', 'takeLast', 'throw' |
290
|
|
|
* @throws \UnexpectedValueException Thrown if a $keyIndex value is not a string or integer |
291
|
|
|
* @throws \Exception Thrown if $duplicatedBehavior is 'throw' and duplicate entries are found. |
292
|
|
|
*/ |
293
|
|
|
public static function extract( |
294
|
|
|
array $input, |
295
|
|
|
$keyIndex, |
296
|
|
|
$valueIndex, |
297
|
|
|
string $duplicateBehavior = 'takeLast' |
298
|
|
|
) : array { |
299
|
|
|
if (!in_array($duplicateBehavior, ['takeFirst', 'takeLast', 'throw'])) { |
300
|
|
|
throw new \InvalidArgumentException("\$duplicateBehavior was not 'takeFirst', 'takeLast', or 'throw'"); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
self::ensureValidKey($keyIndex, '$keyIndex was not a string or integer'); |
304
|
|
|
self::ensureValidKey($valueIndex, '$valueIndex was not a string or integer'); |
305
|
|
|
|
306
|
|
|
$result = []; |
307
|
|
|
foreach ($input as $index => $array) { |
308
|
|
|
self::ensureIsArray($array, '$arrays was not a multi-dimensional array'); |
309
|
|
|
|
310
|
|
|
$key = self::get($array, $keyIndex); |
311
|
|
|
self::ensureValidKey( |
312
|
|
|
$key, |
313
|
|
|
"Value for \$arrays[{$index}][{$keyIndex}] was not a string or integer", |
314
|
|
|
'\\UnexpectedValueException' |
315
|
|
|
); |
316
|
|
|
|
317
|
|
|
$value = self::get($array, $valueIndex); |
318
|
|
|
if (!array_key_exists($key, $result)) { |
319
|
|
|
$result[$key] = $value; |
320
|
|
|
continue; |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
if ($duplicateBehavior === 'throw') { |
324
|
|
|
throw new \Exception("Duplicate entry for '{$key}' found."); |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
if ($duplicateBehavior === 'takeLast') { |
328
|
|
|
$result[$key] = $value; |
329
|
|
|
} |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
return $result; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* Returns the first set {@see isset()} value specified by the given array of keys. |
337
|
|
|
* |
338
|
|
|
* @param array $array The array containing the possible values. |
339
|
|
|
* @param array $keys Array of keys to search for. The first set value will be returned. |
340
|
|
|
* @param mixed $default The default value to return if no set value was found in the array. |
341
|
|
|
* |
342
|
|
|
* @return mixed Returns the found set value or the given default value. |
343
|
|
|
*/ |
344
|
|
|
public static function getFirstSet(array $array, array $keys, $default = null) |
345
|
|
|
{ |
346
|
|
|
foreach ($keys as $key) { |
347
|
|
|
if (isset($array[$key])) { |
348
|
|
|
return $array[$key]; |
349
|
|
|
} |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
return $default; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* Partitions the given $input array into an array of $partitionCount sub arrays. |
357
|
|
|
* |
358
|
|
|
* This is a slight modification of the function suggested on |
359
|
|
|
* http://php.net/manual/en/function.array-chunk.php#75022. This method does not pad with empty partitions and |
360
|
|
|
* ensures positive partition count. |
361
|
|
|
* |
362
|
|
|
* @param array $input The array to partition. |
363
|
|
|
* @param int $partitionCount The maximum number of partitions to create. |
364
|
|
|
* @param bool $preserveKeys Flag to preserve numeric array indexes. Associative indexes are preserved by default. |
365
|
|
|
* |
366
|
|
|
* @return array A multi-dimensional array containing $partitionCount sub arrays. |
367
|
|
|
* |
368
|
|
|
* @throws \InvalidArgumentException Thrown if $partitionCount is not a positive integer. |
369
|
|
|
* @throws \InvalidArgumentException Thrown if $preserveKeys is not a boolean value. |
370
|
|
|
*/ |
371
|
|
|
public static function partition(array $input, int $partitionCount, bool $preserveKeys = false) : array |
372
|
|
|
{ |
373
|
|
|
if ($partitionCount < 1) { |
374
|
|
|
throw new \InvalidArgumentException('$partitionCount must be a positive integer'); |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
$inputLength = count($input); |
378
|
|
|
$partitionLength = floor($inputLength / $partitionCount); |
379
|
|
|
$partitionRemainder = $inputLength % $partitionCount; |
380
|
|
|
$partitions = []; |
381
|
|
|
$sliceOffset = 0; |
382
|
|
|
for ($partitionIndex = 0; $partitionIndex < $partitionCount && $sliceOffset < $inputLength; $partitionIndex++) { |
383
|
|
|
$sliceLength = ($partitionIndex < $partitionRemainder) ? $partitionLength + 1 : $partitionLength; |
384
|
|
|
$partitions[$partitionIndex] = array_slice($input, $sliceOffset, $sliceLength, $preserveKeys); |
385
|
|
|
$sliceOffset += $sliceLength; |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
return $partitions; |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
/** |
392
|
|
|
* Unsets all elements in the given $array specified by $keys |
393
|
|
|
* |
394
|
|
|
* @param array &$array The array containing the elements to unset. |
395
|
|
|
* @param array $keys Array of keys to unset. |
396
|
|
|
* |
397
|
|
|
* @return void |
398
|
|
|
*/ |
399
|
|
|
public static function unsetAll(array &$array, array $keys) |
400
|
|
|
{ |
401
|
|
|
foreach ($keys as $key) { |
402
|
|
|
unset($array[$key]); |
403
|
|
|
} |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
/** |
407
|
|
|
* Convert all empty strings or strings that contain only whitespace to null in the given array |
408
|
|
|
* |
409
|
|
|
* @param array &$array The array containing empty strings |
410
|
|
|
* |
411
|
|
|
* @return void |
412
|
|
|
*/ |
413
|
|
|
public static function nullifyEmptyStrings(array &$array) |
414
|
|
|
{ |
415
|
|
|
foreach ($array as &$value) { |
416
|
|
|
if (is_string($value) && trim($value) === '') { |
417
|
|
|
$value = null; |
418
|
|
|
} |
419
|
|
|
} |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
/** |
423
|
|
|
* Traverses the given $array using the key path specified by $delimitedKey and returns the final value. |
424
|
|
|
* |
425
|
|
|
* Example: |
426
|
|
|
* <br /> |
427
|
|
|
* <pre> |
428
|
|
|
* use TraderInteractive\Util\Arrays; |
429
|
|
|
* $array = [ |
430
|
|
|
* 'db' => [ |
431
|
|
|
* 'host' => 'localhost', |
432
|
|
|
* 'login' => [ |
433
|
|
|
* 'username' => 'scott', |
434
|
|
|
* 'password' => 'tiger', |
435
|
|
|
* ], |
436
|
|
|
* ], |
437
|
|
|
* ]; |
438
|
|
|
* echo Arrays::getNested($array, 'db.login.username'); |
439
|
|
|
* </pre> |
440
|
|
|
* <br /> |
441
|
|
|
* Output: |
442
|
|
|
* <pre> |
443
|
|
|
* scott |
444
|
|
|
* </pre> |
445
|
|
|
* |
446
|
|
|
* @param array $array The array to traverse. |
447
|
|
|
* @param string $delimitedKey A string of keys to traverse into the array. |
448
|
|
|
* @param string $delimiter A string specifiying how the keys are delimited. The default is '.'. |
449
|
|
|
* |
450
|
|
|
* @return mixed The value at the inner most key or null if a key does not exist. |
451
|
|
|
*/ |
452
|
|
|
final public static function getNested(array $array, string $delimitedKey, string $delimiter = '.') |
453
|
|
|
{ |
454
|
|
|
$pointer = $array; |
455
|
|
|
foreach (explode($delimiter, $delimitedKey) as $key) { |
456
|
|
|
if (is_array($pointer) && array_key_exists($key, $pointer)) { |
457
|
|
|
$pointer = $pointer[$key]; |
458
|
|
|
continue; |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
return null; |
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
return $pointer; |
465
|
|
|
} |
466
|
|
|
|
467
|
|
|
/** |
468
|
|
|
* Changes the case of all keys in an array. Numbered indices are left as is. |
469
|
|
|
* |
470
|
|
|
* @param array $input The array to work on. |
471
|
|
|
* @param integer $case The case to which the keys should be set. |
472
|
|
|
* |
473
|
|
|
* @return array Returns an array with its keys case changed. |
474
|
|
|
*/ |
475
|
|
|
public static function changeKeyCase(array $input, int $case = self::CASE_LOWER) : array |
476
|
|
|
{ |
477
|
|
|
if ($case & self::CASE_UNDERSCORE) { |
478
|
|
|
$copy = []; |
479
|
|
|
foreach ($input as $key => $value) { |
480
|
|
|
$copy[preg_replace("/([a-z])([A-Z0-9])/", '$1_$2', $key)] = $value; |
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
$input = $copy; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
if ($case & self::CASE_CAMEL_CAPS) { |
487
|
|
|
$copy = []; |
488
|
|
|
foreach ($input as $key => $value) { |
489
|
|
|
$key = implode(' ', array_filter(preg_split('/[^a-z0-9]/i', $key))); |
490
|
|
|
$key = lcfirst(str_replace(' ', '', ucwords(strtolower($key)))); |
491
|
|
|
$copy[$key] = $value; |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
$input = $copy; |
495
|
|
|
} |
496
|
|
|
|
497
|
|
|
unset($copy); //gc |
498
|
|
|
|
499
|
|
|
if ($case & self::CASE_UPPER) { |
500
|
|
|
$input = array_change_key_case($input, \CASE_UPPER); |
501
|
|
|
} |
502
|
|
|
|
503
|
|
|
if ($case & self::CASE_LOWER) { |
504
|
|
|
$input = array_change_key_case($input, \CASE_LOWER); |
505
|
|
|
} |
506
|
|
|
|
507
|
|
|
return $input; |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
/** |
511
|
|
|
* Converts a multi-dimensional array into a single associative array whose keys are the concatinated keys |
512
|
|
|
* |
513
|
|
|
* @param array $input The array to flatten |
514
|
|
|
* @param string $delimiter The separator for the concatinated keys. |
515
|
|
|
* |
516
|
|
|
* @return array The flattened array |
517
|
|
|
*/ |
518
|
|
|
final public static function flatten(array $input, string $delimiter = '.') : array |
519
|
|
|
{ |
520
|
|
|
$args = func_get_args(); |
521
|
|
|
$prefix = count($args) === 3 ? array_pop($args) : ''; |
522
|
|
|
$result = []; |
523
|
|
|
foreach ($input as $key => $value) { |
524
|
|
|
$newKey = $prefix . (empty($prefix) ? '' : $delimiter) . $key; |
525
|
|
|
if (is_array($value)) { |
526
|
|
|
$result = array_merge($result, self::flatten($value, $delimiter, $newKey)); |
527
|
|
|
continue; |
528
|
|
|
} |
529
|
|
|
|
530
|
|
|
$result[$newKey] = $value; |
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
return $result; |
534
|
|
|
} |
535
|
|
|
|
536
|
|
|
/** |
537
|
|
|
* Returns all elements in the given $input array which contain the specifed $targetKey index. |
538
|
|
|
* |
539
|
|
|
* @param array $input The multi-dimensional array to check. |
540
|
|
|
* @param string|integer $targetKey The key to search for. |
541
|
|
|
* |
542
|
|
|
* @return array All elements of $input which contained $targetKey element with original keys preserved. |
543
|
|
|
*/ |
544
|
|
|
final public static function getAllWhereKeyExists(array $input, $targetKey) : array |
545
|
|
|
{ |
546
|
|
|
$result = []; |
547
|
|
|
foreach ($input as $key => $value) { |
548
|
|
|
if (array_key_exists($targetKey, $value)) { |
549
|
|
|
$result[$key] = $value; |
550
|
|
|
} |
551
|
|
|
} |
552
|
|
|
|
553
|
|
|
return $result; |
554
|
|
|
} |
555
|
|
|
|
556
|
|
|
private static function ensureValidKey( |
557
|
|
|
$key, |
558
|
|
|
string $message, |
559
|
|
|
string $exceptionClass = '\\InvalidArgumentException' |
560
|
|
|
) { |
561
|
|
|
if (!is_string($key) && !is_int($key)) { |
562
|
|
|
$reflectionClass = new \ReflectionClass($exceptionClass); |
563
|
|
|
throw $reflectionClass->newInstanceArgs([$message]); |
564
|
|
|
} |
565
|
|
|
} |
566
|
|
|
|
567
|
|
|
private static function ensureIsArray( |
568
|
|
|
$value, |
569
|
|
|
string $message, |
570
|
|
|
string $exceptionClass = '\\InvalidArgumentException' |
571
|
|
|
) { |
572
|
|
|
if (!is_array($value)) { |
573
|
|
|
$reflectionClass = new \ReflectionClass($exceptionClass); |
574
|
|
|
throw $reflectionClass->newInstanceArgs([$message]); |
575
|
|
|
} |
576
|
|
|
} |
577
|
|
|
} |
578
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.