GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 6e41ae...f215c9 )
by t
06:13 queued 12s
created

Arrays   F

Complexity

Total Complexity 129

Size/Duplication

Total Lines 951
Duplicated Lines 0 %

Test Coverage

Coverage 89.61%

Importance

Changes 28
Bugs 2 Features 0
Metric Value
eloc 253
c 28
b 2
f 0
dl 0
loc 951
ccs 250
cts 279
cp 0.8961
rs 2
wmc 129

39 Methods

Rating   Name   Duplication   Size   Complexity  
A indexBy() 0 16 4
B columns() 0 30 9
A transposed() 0 9 3
B count() 0 22 7
B search() 0 12 7
A toPart() 0 7 1
A detectFirst() 0 8 3
A combine() 0 10 3
A dimension() 0 15 5
A keyFirst() 0 10 5
A toCellArray() 0 12 3
A decrement() 0 4 1
A valueExistsAll() 0 3 1
A map() 0 11 4
A rangeGenerator() 0 14 5
B merge() 0 21 8
A lists() 0 15 5
A export() 0 11 2
A queueNumber() 0 18 5
A isIndexed() 0 7 2
A last() 0 14 4
A combines() 0 8 2
A keyExistsAll() 0 4 1
A fill() 0 10 3
A first() 0 13 4
A some() 0 7 2
A increment() 0 4 1
A values() 0 3 1
A fromCsv() 0 8 2
A isAssoc() 0 7 2
A column() 0 20 6
A exceptedKeys() 0 4 1
A valueExistsSome() 0 3 1
A colRowCount() 0 3 1
A explode() 0 8 2
A keyExistsSome() 0 3 1
A in() 0 11 3
A detectAll() 0 13 4
A keyLast() 0 10 5

How to fix   Complexity   

Complex Class

Complex classes like Arrays often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Arrays, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Class Arrays
4
 *
5
 * @link https://www.icy2003.com/
6
 * @author icy2003 <[email protected]>
7
 * @copyright Copyright (c) 2017, icy2003
8
 */
9
10
namespace icy2003\php\ihelpers;
11
12
use icy2003\php\C;
13
use icy2003\php\I;
14
15
/**
16
 * 数组类
17
 *
18
 * 常见数组格式的拼装和处理
19
 *
20
 * @test icy2003\php_tests\ihelpers\ArraysTest
21
 */
22
class Arrays
23
{
24
25
    /**
26
     * 以各个元素的某字段值作为键重新指回该元素,此值对于该元素需唯一
27
     *
28
     * @param array  $array 元素可以为数组或者对象
29
     * @param string $index 用来作为键的某字段,不能为 null
30
     * @param boolean $isMerge 是否合并相同键的项到数组,默认否(也就是后者覆盖前者)
31
     *
32
     * @return array
33
     *
34
     * @tested
35
     */
36 1
    public static function indexBy($array, $index, $isMerge = false)
37
    {
38 1
        $result = [];
39 1
        foreach ($array as $row) {
40 1
            $indexValue = I::get($row, $index);
41 1
            if (null === $indexValue) {
42 1
                return [];
43
            }
44 1
            if (false === $isMerge) {
45 1
                $result[$indexValue] = $row;
46
            } else {
47 1
                $result[$indexValue][] = $row;
48
            }
49
        }
50
51 1
        return $result;
52
    }
53
54
    /**
55
     * 选取数组中指定键的某几列
56
     *
57
     * - 简单理解就是:从数据库里查出来几条数据,只拿其中的几个属性
58
     * - 当 $dimension 为 2 时,理解为从几条数据里拿属性
59
     * - 当 $dimension 为 1 时,理解为从一条数据里拿属性
60
     *
61
     * @param array $array
62
     * @param array $keys 某几项字段,支持 I::get 的键格式,如果是键值对,键会被设置为键
63
     *      - [a, b]:查找 a 和 b
64
     *      - [a.b, c]:查找 a.b 和 c
65
     *      - [a => b]:查找 b 并且设置该项的键为 a
66
     * @param integer $dimension 维度,只能为 1 或 2,默认 2,表示处理二维数组
67
     *
68
     * @return array
69
     *
70
     * @tested
71
     */
72 1
    public static function columns($array, $keys = null, $dimension = 2)
73
    {
74 1
        if (null === $keys) {
75 1
            return $array;
76
        }
77 1
        $result = [];
78 1
        if (2 === $dimension) {
79 1
            foreach ($array as $k => $row) {
80 1
                foreach ($keys as $k1 => $key) {
81 1
                    $value = I::get($row, $key);
82 1
                    if (is_numeric($k1)) {
83 1
                        $result[$k][$key] = $value;
84
                    } else {
85
                        $result[$k][$k1] = $value;
86
                    }
87
                }
88
            }
89
        }
90 1
        if (1 === $dimension) {
91 1
            foreach ($keys as $k1 => $key) {
92 1
                $value = I::get($array, $key);
93 1
                if (is_numeric($k1)) {
94 1
                    $result[$key] = $value;
95
                } else {
96
                    $result[$k1] = $value;
97
                }
98
            }
99
        }
100
101 1
        return $result;
102
    }
103
104
    /**
105
     * 返回二维(或者更高)数组中指定键的一列的所有值
106
     *
107
     * - array_column 要求 PHP >= 5.5,这个是兼容 5.5 以下的,并且在不传入 $index 时,键将原样保持
108
     * - 如果需要取某几项,使用 Arrays::columns
109
     * - 简单理解就是:从数据库里查出来几条数据,只要其中某个属性的所有值
110
     * - USE_CUSTOM
111
     *
112
     * @see http://php.net/array_column
113
     *
114
     * @param array $array
115
     * @param string $column 需要被取出来的字段
116
     * @param string $index 作为 index 的字段
117
     *
118
     * @return array
119
     *
120
     * @tested
121
     */
122 2
    public static function column($array, $column, $index = null)
123
    {
124 2
        if (function_exists('array_column') && false === I::ini('USE_CUSTOM')) {
125 2
            $result = array_column($array, $column, $index);
126 2
            if(null === $index){
127 2
                $result = self::combine(array_keys($array), $result);
128
            }
129 2
            return $result;
130
        } else {
131 1
            $result = [];
132 1
            foreach ($array as $key => $row) {
133 1
                $data = I::get($row, $column);
134 1
                if (null === $index) {
135 1
                    $result[$key] = $data;
136
                } else {
137 1
                    $result[$row[$index]] = $data;
138
                }
139
            }
140
141 1
            return $result;
142
        }
143
    }
144
145
    /**
146
     * 创建一个数组,用一个数组的值作为其键名,另一个数组的值作为其值
147
     *
148
     * - array_combine:两个数组元素个数不一致将报错
149
     * - 在两个数组元素个数不一致时,以键为准:
150
     *      1.键比值多,值都被填充为 null
151
     *      2.值比键多,值被舍去
152
     * ```
153
     *
154
     * @see http://php.net/array_combine
155
     *
156
     * @param array $keys
157
     * @param array $values
158
     *
159
     * @return array
160
     *
161
     * @tested
162
     */
163 4
    public static function combine($keys, $values)
164
    {
165 4
        if (count($keys) == count($values)) {
166 4
            return (array)array_combine($keys, $values);
167
        }
168 1
        $array = [];
169 1
        foreach ($keys as $index => $key) {
170 1
            $array[$key] = I::get($values, $index);
171
        }
172 1
        return $array;
173
    }
174
175
    /**
176
     * 递归地合并多个数组
177
     *
178
     * - array_merge_recursive:如果有相同的键,后者会覆盖前者
179
     * - 此函数会合并两个相同键的值到一个数组里
180
     *
181
     * @see http://php.net/array_merge_recursive
182
     *
183
     * @param array $a 数组1
184
     * @param array $b 数组2(可以任意个数组)
185
     *
186
     * @return array
187
     *
188
     * @tested
189
     */
190 37
    public static function merge($a, $b)
191
    {
192 37
        $args = func_get_args();
193 37
        $res = array_shift($args);
194 37
        while (!empty($args)) {
195 37
            foreach (array_shift($args) as $k => $v) {
196 3
                if (is_int($k)) {
197 2
                    if (array_key_exists($k, $res)) {
198 2
                        $res[] = $v;
199
                    } else {
200 2
                        $res[$k] = $v;
201
                    }
202 2
                } elseif (is_array($v) && isset($res[$k]) && is_array($res[$k])) {
203 1
                    $res[$k] = self::merge($res[$k], $v);
204
                } else {
205 2
                    $res[$k] = $v;
206
                }
207
            }
208
        }
209
210 37
        return $res;
211
    }
212
213
    /**
214
     *  range 的性能优化版
215
     *
216
     * @see http://php.net/manual/zh/language.generators.overview.php
217
     * @version PHP >= 5.5
218
     *
219
     * @param integer $start 开始
220
     * @param integer $end 结束
221
     * @param integer $step 步长
222
     *
223
     * @return \Generator
224
     *
225
     * @tested
226
     */
227 8
    public static function rangeGenerator($start, $end, $step = 1)
228
    {
229 8
        if ($start < $end) {
230 7
            C::assertTrue($step > 0, '步长必须大于 0');
231 7
            for ($i = $start; $i <= $end; $i += $step) {
232 7
                yield $i;
233
            }
234 3
        } elseif ($start > $end) {
235 1
            C::assertTrue($step < 0, '步长必须小于 0');
236 1
            for ($i = $start; $i >= $end; $i += $step) {
237 1
                yield $i;
238
            }
239
        } else {
240 2
            yield $start;
241
        }
242 8
    }
243
244
    /**
245
     * 找到符合条件的第一项
246
     *
247
     * @param array $array
248
     * @param callback $callback 条件回调,结果为 true 的第一项会被取出
249
     *
250
     * @return mixed
251
     *
252
     * @tested
253
     */
254 1
    public static function detectFirst($array, $callback)
255
    {
256 1
        foreach ($array as $key => $item) {
257 1
            if (true === I::call($callback, [$item, $key])) {
258 1
                return $item;
259
            }
260
        }
261 1
        return null;
262
    }
263
264
    /**
265
     * 找到符合条件的所有项
266
     *
267
     * @param array $array
268
     * @param callback $callback 条件回调,结果为 true 的所有项会被取出
269
     * @param callback $filter 对符合条件的项进行回调处理并返回
270
     *
271
     * @return array
272
     *
273
     * @tested
274
     */
275 1
    public static function detectAll($array, $callback, $filter = null)
276
    {
277 1
        $all = [];
278 1
        foreach ($array as $key => $item) {
279 1
            if (true === I::call($callback, [$item, $key])) {
280 1
                if (null !== $filter) {
281 1
                    $all[$key] = I::call($filter, [$item, $key]);
282
                } else {
283 1
                    $all[$key] = $item;
284
                }
285
            }
286
        }
287 1
        return $all;
288
    }
289
290
    /**
291
     * 返回数组的最后一个元素的键
292
     *
293
     * - array_key_last:需要 PHP7.3.0+ 才能支持
294
     * - USE_CUSTOM
295
     *
296
     * @param array $array
297
     *
298
     * @return string|null
299
     *
300
     * @tested
301
     */
302 1
    public static function keyLast($array)
303
    {
304 1
        if (!is_array($array) || empty($array)) {
305 1
            return null;
306
        }
307 1
        if (function_exists('array_key_last') && false === I::ini('USE_CUSTOM')) {
308 1
            return array_key_last($array);
309
        }
310 1
        end($array);
311 1
        return key($array);
312
    }
313
314
    /**
315
     * 返回数组的第一个元素的键
316
     *
317
     * - array_key_first:需要 PHP7.3.0+ 才能支持
318
     * - USE_CUSTOM
319
     *
320
     * @param array $array
321
     *
322
     * @return string|null
323
     *
324
     * @tested
325
     */
326 1
    public static function keyFirst($array)
327
    {
328 1
        if (!is_array($array) || empty($array)) {
329 1
            return null;
330
        }
331 1
        if (function_exists('array_key_first') && false === I::ini('USE_CUSTOM')) {
332 1
            return array_key_first($array);
333
        }
334 1
        reset($array);
335 1
        return key($array);
336
    }
337
338
    /**
339
     * 获取数组的维度
340
     *
341
     * @param array $array 多维数组
342
     *
343
     * @return integer
344
     *
345
     * @tested
346
     */
347 1
    public static function dimension($array)
348
    {
349 1
        if (!is_array($array)) {
350 1
            return 0;
351
        }
352 1
        $max = 1;
353 1
        foreach ($array as $value) {
354 1
            if (is_array($value)) {
355 1
                $d = self::dimension($value) + 1;
356 1
                if ($d > $max) {
357 1
                    $max = $d;
358
                }
359
            }
360
        }
361 1
        return $max;
362
    }
363
364
    /**
365
     * 判断数组是不是关联数组
366
     *
367
     * @param array $array
368
     *
369
     * @return boolean
370
     *
371
     * @tested
372
     */
373 1
    public static function isAssoc($array)
374
    {
375 1
        if (is_array($array)) {
376 1
            $keys = array_keys($array);
377 1
            return $keys !== array_keys($keys);
378
        }
379 1
        return false;
380
    }
381
382
    /**
383
     * 判断数组是不是索引数组
384
     *
385
     * 索引数组必须是下标从 0 开始的数组,键是数字还是字符串类型的数字无所谓
386
     *
387
     * @param array $array
388
     *
389
     * @return boolean
390
     *
391
     * @tested
392
     */
393 1
    public static function isIndexed($array)
394
    {
395 1
        if (is_array($array)) {
396 1
            $keys = array_keys($array);
397 1
            return $keys === array_keys($keys);
398
        }
399 1
        return false;
400
    }
401
402
    /**
403
     * 返回数组的顺数第 n 个元素,其中 n >= 1 且为整数,空数组直接返回 null
404
     *
405
     * - 支持关联数组,超过数组长度会对数组长度求余后查找
406
     *
407
     * @param array $array
408
     * @param int $pos 顺数第 n 个,默认 1
409
     *
410
     * @return mixed
411
     *
412
     * @tested
413
     */
414 3
    public static function first($array, $pos = 1)
415
    {
416 3
        if (0 === ($count = self::count($array))) {
417 1
            return null;
418
        }
419 3
        $p = $pos % $count;
420 3
        if (0 === $p) {
421 2
            $p = $count;
422
        }
423 3
        for ($i = 1; $i < $p; $i++) {
424 1
            next($array);
425
        }
426 3
        return current($array);
427
    }
428
429
    /**
430
     * 返回数组的倒数第 n 个元素,其中 n >= 1 且为整数,空数组直接返回 null
431
     *
432
     * - 支持关联数组,超过数组长度会对数组长度求余后查找
433
     *
434
     * @param array $array
435
     * @param int $pos 倒数第 n 个,默认 1
436
     *
437
     * @return mixed
438
     *
439
     * @tested
440
     */
441 1
    public static function last($array, $pos = 1)
442
    {
443 1
        if (0 === ($count = self::count($array))) {
444 1
            return null;
445
        }
446 1
        $p = $pos % $count;
447 1
        if (0 === $p) {
448 1
            $p = $count;
449
        }
450 1
        end($array);
451 1
        for ($i = 1; $i < $p; $i++) {
452 1
            prev($array);
453
        }
454 1
        return current($array);
455
    }
456
457
    /**
458
     * 计算数组中的单元数目
459
     *
460
     * - count:在非数组情况下,除了 null 会返回 0,其他都返回 1,囧
461
     * - $callback 参数用于对符合条件的项做筛选
462
     *
463
     * @param array|mixed $array 数组
464
     * @param callback|mixed $callback 回调,返回回调值为 true 的项,如果此参数是非回调类型,表示查询和此值严格相等的项
465
     * @param boolean $isStrict 是否为严格模式,如果为 false,回调值为 true 值的也会返回,为字符串时不使用严格比较
466
     *
467
     * @return integer
468
     *
469
     * @tested
470
     */
471 10
    public static function count($array, $callback = null, $isStrict = true)
472
    {
473 10
        $count = 0;
474 10
        if (is_array($array)) {
475 10
            if (null === $callback) {
476 10
                return count($array);
477
            } else {
478 2
                $function = $callback;
479 2
                if (false === is_callable($callback)) {
480
                    $function = function($row) use ($callback, $isStrict) {
481 2
                        return true === $isStrict ? $row === $callback : $row == $callback;
482 2
                    };
483
                }
484 2
                foreach ($array as $key => $row) {
485 2
                    if (true === I::call($function, [$row, $key])) {
486 2
                        $count++;
487
                    }
488
                }
489
490
            }
491
        }
492 2
        return $count;
493
    }
494
495
    /**
496
     * 返回指定长度的数组,不足的值设置为 null
497
     *
498
     * @param array $array
499
     * @param integer $count 指定长度
500
     * @param callback $callback 回调参数:数组的值、数组的键
501
     *
502
     * @return array
503
     *
504
     * @tested
505
     */
506 2
    public static function lists($array, $count = null, $callback = null)
507
    {
508 2
        null === $count && $count = self::count($array);
509 2
        $arrayCount = self::count($array);
510 2
        if ($arrayCount >= $count) {
511 2
            $return = $array;
512
        } else {
513 1
            $return = self::merge($array, self::fill(0, $count - $arrayCount, null));
514
        }
515 2
        if (null !== $callback) {
516 1
            foreach ($return as $key => $value) {
517 1
                $return[$key] = I::call($callback, [$value, $key]);
518
            }
519
        }
520 2
        return $return;
521
    }
522
523
    /**
524
     * 获取指定某些键的项的值
525
     *
526
     * @param array $array
527
     * @param array|string $keys 数组或逗号字符串
528
     *
529
     * @return array
530
     *
531
     * @tested
532
     */
533 1
    public static function values($array, $keys = null)
534
    {
535 1
        return array_values(self::some($array, $keys));
536
    }
537
538
    /**
539
     * 获取指定某些键的项
540
     *
541
     * @param array $array
542
     * @param array|string $keys 数组或都好字符串
543
     *
544
     * @return array
545
     *
546
     * @tested
547
     */
548 2
    public static function some($array, $keys = null)
549
    {
550 2
        if (null === $keys) {
551 1
            return $array;
552
        }
553 2
        $keys = Strings::toArray($keys);
554 2
        return array_intersect_key($array, array_flip($keys));
555
    }
556
557
    /**
558
     * 获取指定除了某些键的项
559
     *
560
     * @param array $array
561
     * @param array|string $keys
562
     *
563
     * @return array
564
     *
565
     * @tested
566
     */
567 1
    public static function exceptedKeys($array, $keys)
568
    {
569 1
        $keys = Strings::toArray($keys);
570 1
        return array_diff_key($array, array_flip($keys));
571
    }
572
573
    /**
574
     * 检查数组里是否有指定的所有键名或索引
575
     *
576
     * - array_key_exists:检测一个指定的键
577
     * - Arrays::keyExistsOne:检测数组里是否存在指定的某些键
578
     *
579
     * @param array $keys 要检查的键
580
     * @param array $array
581
     * @param array $diff 引用返回不包含的键
582
     *
583
     * @return boolean
584
     *
585
     * @tested
586
     */
587 1
    public static function keyExistsAll($keys, $array, &$diff = null)
588
    {
589
590 1
        return I::isEmpty($diff = array_diff($keys, array_keys($array)));
591
    }
592
593
    /**
594
     * 检查数组里是否有指定的某些键名或索引
595
     *
596
     * @param array $keys 要检查的键
597
     * @param array $array
598
     * @param array $find 引用返回包含的键
599
     *
600
     * @return boolean
601
     *
602
     * @tested
603
     */
604 1
    public static function keyExistsSome($keys, $array, &$find = null)
605
    {
606 1
        return !I::isEmpty($find = array_intersect($keys, array_keys($array)));
607
    }
608
609
    /**
610
     * 检查数组里是否有指定的所有值
611
     *
612
     * @param array $values 要检查的值
613
     * @param array $array
614
     * @param array $diff 引用返回不包含的值
615
     *
616
     * @return boolean
617
     *
618
     * @tested
619
     */
620 1
    public static function valueExistsAll($values, $array, &$diff = null)
621
    {
622 1
        return I::isEmpty($diff = array_diff($values, array_values($array)));
623
    }
624
625
    /**
626
     * 检查数组里是否有指定的某些值
627
     *
628
     * @param array $values 要检查的值
629
     * @param array $array
630
     * @param array $find 引用返回包含的值
631
     *
632
     * @return boolean
633
     *
634
     * @tested
635
     */
636 1
    public static function valueExistsSome($values, $array, &$find = null)
637
    {
638 1
        return !I::isEmpty($find = array_intersect($values, array_values($array)));
639
    }
640
641
    /**
642
     * 参照 PHP 的 array_combine 函数,array_combine 得到的是一行记录的格式,该函数得到多行
643
     *
644
     * - arrays 里的每个数组会和 keys 使用 self::combine 合并,最终合并成为一个二维数组
645
     *
646
     * @param array $keys 作为键的字段
647
     * @param array $arrays
648
     *
649
     * @return array
650
     *
651
     * @tested
652
     */
653 1
    public static function combines($keys, $arrays)
654
    {
655 1
        $result = [];
656 1
        foreach ($arrays as $k => $array) {
657 1
            $result[$k] = self::combine($keys, $array);
658
        }
659
660 1
        return $result;
661
    }
662
663
    /**
664
     * 把数组里逗号字符串拆分,并且去掉重复的部分
665
     *
666
     * @param array $array
667
     *
668
     * @return array
669
     *
670
     * @tested
671
     */
672 2
    public static function toPart($array)
673
    {
674 2
        return array_values(
675 2
            array_filter(
676 2
                array_keys(
677 2
                    array_flip(
678 2
                        explode(',', implode(',', $array))
679
                    )
680
                )
681
            )
682
        );
683
    }
684
685
    /**
686
     * 矩阵转置
687
     *
688
     * @param array $array 待转置的矩阵
689
     *
690
     * @return array
691
     *
692
     * @tested
693
     */
694 1
    public static function transposed($array)
695
    {
696 1
        $data = [];
697 1
        foreach ($array as $r => $row) {
698 1
            foreach ($row as $c => $col) {
699 1
                $data[$c][$r] = $col;
700
            }
701
        }
702 1
        return $data;
703
    }
704
705
    /**
706
     * 普通二维数组转化成 Excel 单元格二维数组
707
     *
708
     * @param array $array
709
     *
710
     * @return array
711
     *
712
     * @tested
713
     */
714 1
    public static function toCellArray($array)
715
    {
716 1
        $data = [];
717 1
        $rowIndex = 0;
718 1
        foreach ($array as $row) {
719 1
            $rowIndex++;
720 1
            $colIndex = 'A';
721 1
            foreach ($row as $col) {
722 1
                $data[$rowIndex][$colIndex++] = $col;
723
            }
724
        }
725 1
        return $data;
726
    }
727
728
    /**
729
     * 返回矩阵的列数和行数
730
     *
731
     * - 返回两个元素的一维数组,第一个元素表示矩阵的列数,第二个元素表示矩阵的行数
732
     *
733
     * @param array $array
734
     *
735
     * @return array
736
     *
737
     * @tested
738
     */
739 2
    public static function colRowCount($array)
740
    {
741 2
        return [self::count(self::first($array)), self::count($array)];
742
    }
743
744
    /**
745
     * 用给定的值填充数组
746
     *
747
     * - array_fill:第一参数在为负的时候,生成的数组的第二个元素是从 0 开始的!
748
     *
749
     * @param int $startIndex 返回的数组的第一个索引值
750
     * @param int $num 插入元素的数量。如果为 0 或者负数,则返回空数组
751
     * @param mixed $value 用来填充的值
752
     *
753
     * @return array
754
     *
755
     * @tested
756
     */
757 2
    public static function fill($startIndex, $num, $value)
758
    {
759 2
        if ($num <= 0) {
760 1
            return [];
761
        }
762 2
        $array = [];
763 2
        foreach (self::rangeGenerator($startIndex, $startIndex + $num - 1) as $key) {
764 2
            $array[$key] = $value;
765
        }
766 2
        return $array;
767
    }
768
769
    /**
770
     * 让 var_export 返回 `[]` 的格式
771
     *
772
     * @param mixed $expression 变量
773
     * @param bool $return 默认值 为 true,即返回字符串而不是输出
774
     *
775
     * @return mixed
776
     *
777
     * @tested
778
     */
779 1
    public static function export($expression, $return = true)
780
    {
781 1
        $export = var_export($expression, true);
782 1
        $export = preg_replace("/^([ ]*)(.*)/m", '$1$1$2', $export);
783 1
        $array = preg_split("/\r\n|\n|\r/", $export);
784 1
        $array = preg_replace(["/\s*array\s\($/", "/\)(,)?$/", "/\s=>\s$/"], [null, ']$1', ' => ['], $array);
785 1
        $export = implode(PHP_EOL, array_filter(["["] + $array));
786 1
        if (true === $return) {
787 1
            return $export;
788
        } else {
789 1
            echo $export;
790
        }
791 1
    }
792
793
    /**
794
     * 将 CSV 文本转成数组
795
     *
796
     * @param string $csvString
797
     *
798
     * @return array
799
     *
800
     * @tested
801
     */
802 1
    public static function fromCsv($csvString)
803
    {
804 1
        $lines = explode(PHP_EOL, $csvString);
805 1
        $array = [];
806 1
        foreach ($lines as $line) {
807 1
            $array[] = explode(',', $line);
808
        }
809 1
        return $array;
810
    }
811
812
    /**
813
     * 在数组中搜索给定的值,如果成功则返回首个相应的键名
814
     *
815
     * - 第一参数如果不是回调函数,则此方法等同于 array_search
816
     * - 第一参数如果是回调函数,则找到的条件为:回调值为 true
817
     * - 第三参数如果是 false,则回调值只需要 true 值即可(例如:1)
818
     *
819
     * @param mixed|callback $search 搜索的值
820
     * @param array $array 这个数组
821
     * @param boolean $isStrict 是否检查完全相同的元素
822
     *
823
     * @return mixed|false
824
     *
825
     * @tested
826
     */
827 1
    public static function search($search, $array, $isStrict = false)
828
    {
829 1
        if (false === is_callable($search)) {
830 1
            return array_search($search, $array, $isStrict);
831
        }
832 1
        foreach ($array as $key => $row) {
833 1
            $result = I::call($search, [$row]);
834 1
            if ((true === $isStrict && true === $result) || (false === $isStrict && true == $result)) {
835 1
                return $key;
836
            }
837
        }
838 1
        return false;
839
    }
840
841
    /**
842
     * 递增数组的一个值并返回
843
     *
844
     * - 如果该值不存在,则默认为 0
845
     *
846
     * @param array $array 引用返回数组
847
     * @param string $key
848
     * @param integer $step 步长,默认 1
849
     *
850
     * @return double|integer
851
     *
852
     * @tested
853
     */
854 1
    public static function increment(&$array, $key, $step = 1)
855
    {
856 1
        $array[$key] = I::get($array, $key, 0) + $step;
857 1
        return $array[$key];
858
    }
859
860
    /**
861
     * 递减数组的一个值并返回
862
     *
863
     * - 如果该值不存在,则默认为 0
864
     *
865
     * @param array $array 引用返回数组
866
     * @param string $key
867
     * @param integer $step 步长,默认 1
868
     *
869
     * @return double|integer
870
     *
871
     * @tested
872
     */
873 1
    public static function decrement(&$array, $key, $step = 1)
874
    {
875 1
        $array[$key] = I::get($array, $key, 0) - $step;
876 1
        return $array[$key];
877
    }
878
879
    /**
880
     * in_array 的扩展
881
     *
882
     * @param mixed $value
883
     * @param array|mixed $array
884
     * @param boolean $isStrict 是否严格匹配,默认 false,即不严格
885
     * @param boolean $ignoreCase 是否忽略大小写,默认 false,不忽略
886
     *
887
     * @return boolean
888
     */
889 3
    public static function in($value, $array, $isStrict = false, $ignoreCase = false)
890
    {
891 3
        if (false === is_array($array)) {
892 1
            return false;
893
        }
894 3
        if (false === $ignoreCase) {
895 1
            return in_array($value, $array, $isStrict);
896
        } else {
897 3
            $value = Json::decode(strtolower(Json::encode($value)));
898 3
            $array = (array)Json::decode(strtolower(Json::encode($array)));
899 3
            return in_array($value, $array, $isStrict);
900
        }
901
    }
902
903
    /**
904
     * 对一个数组执行回调并返回新数组
905
     *
906
     * @param array|mixed $array
907
     * @param callback $valueCallback 对值的回调
908
     * @param callback|null $keyCallback 对键的回调
909
     *
910
     * @return array
911
     */
912
    public static function map($array, $valueCallback, $keyCallback = null)
913
    {
914
        $return = [];
915
        if (is_array($array)) {
916
            foreach ($array as $key => $value) {
917
                $callValue = I::call($valueCallback, [$value, $key]);
918
                $callKey = null === $keyCallback ? $key : I::call($keyCallback, [$value, $key]);
919
                $return[$callKey] = $callValue;
920
            }
921
        }
922
        return $return;
923
    }
924
925
    /**
926
     * 排队取号
927
     *
928
     * - 含义:给定只包含数字的索引数组,索引数组的值作为号码从小到大排序,如果中间漏掉某个号码,则返回该号码,否则返回最后一位号码,并且引用返回该队列
929
     * - 号码的值从 0 开始
930
     * - 例子:[4, 0, 1] 将引用返回数组[4, 0, 1, 2],函数返回 2
931
     *
932
     * @param array $array
933
     * @param integer $begin 开始的号码,默认为 0
934
     *
935
     * @return integer
936
     */
937
    public static function queueNumber(&$array, $begin = 0)
938
    {
939
        $array2 = $array;
940
        sort($array2);
941
        $next = $begin;
942
        foreach ($array2 as $v) {
943
            if ($v > $next) {
944
                break;
945
            } elseif ($v < $next) {
946
                if ($v + 1 > $next) {
947
                    $next = $v + 1;
948
                }
949
            } else {
950
                $next++;
951
            }
952
        }
953
        array_push($array, $next);
954
        return $next;
955
    }
956
957
    /**
958
     * 将一维数组的每项用分隔符拆分,得到两部分分别设置为新数组的键和值
959
     *
960
     * @param string $delimiter 分隔符
961
     * @param array $array
962
     *
963
     * @return array
964
     */
965
    public static function explode($delimiter, $array)
966
    {
967
        $return = [];
968
        foreach ($array as $row) {
969
            list($k, $v) = Arrays::lists(explode($delimiter, $row), 2);
970
            $return[$k] = $v;
971
        }
972
        return $return;
973
    }
974
975
}
976