ArrayUtil::mergeRecursiveDistinct()   D
last analyzed

Complexity

Conditions 9
Paths 6

Size

Total Lines 31
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 31
rs 4.909
cc 9
eloc 17
nc 6
nop 0
1
<?php
2
3
/**
4
 * This file is part of the Axstrad library.
5
 *
6
 * (c) Dan Kempster <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @copyright 2014-2015 Dan Kempster <[email protected]>
12
 */
13
14
namespace Axstrad\Common\Util;
15
16
use Axstrad\Common\Exception\InvalidArgumentException;
17
18
/**
19
 * Axstrad\Common\Util\ArrayUtil
20
 *
21
 * A collection of array functions.
22
 *
23
 * @author Dan Kempster <[email protected]>
24
 * @package Axstrad\Common
25
 * @subpackage Util
26
 */
27
final class ArrayUtil
28
{
29
    /**
30
     * Decompiles an array path string into an array of the path elements.
31
     *
32
     * For example
33
     *
34
     *     $result = ArrayUtil::decompilePath('foo.doo.goo');
35
     *     $result = ArrayUtil::decompilePath('foo[doo][goo]');
36
     *     $result = ArrayUtil::decompilePath('[foo][doo][goo]');
37
     *
38
     *     // Outputs
39
     *     array(
40
     *         'foo',
41
     *         'doo',
42
     *         'goo',
43
     *     );
44
     *
45
     * @param  string $path
46
     * @return array
47
     */
48
    public static function decompilePath($path)
49
    {
50
        if (is_object($path) && ! method_exists($path, '__toString')) {
51
            throw InvalidArgumentException::create('scalar', $path);
52
        }
53
        $path = (string) $path;
54
55
        if (preg_match('/^[a-z0-9_]*\./i', $path)) {
56
            return explode('.', $path);
57
        }
58
        else {
59
            $parts = array_filter(explode('[', $path), function (&$value) {
60
                $value = trim($value, ']');
61
                return ! empty($value);
62
            });
63
            return array_values($parts);
64
        }
65
    }
66
67
    /**
68
     * Return a value from an array using an array path.
69
     *
70
     * If the $arrayPath's value doesn't exist within $array return $default.
71
     *
72
     * @param  string $arrayPath
73
     * @param  array  $array
74
     * @param  mixed  $default A default value to use if _key_ isn't set in _array_.
75
     * @return mixed
76
     * @uses   decompilePath To decompile $arrayPath.
77
     */
78
    public static function get($arrayPath, array $array, $default = null)
79
    {
80
        $pathKeys = self::decompilePath($arrayPath);
81
82
        $_a = $array;
83
        foreach ($pathKeys as $key) {
84
            if ( ! isset($_a[$key])) {
85
                return $default;
86
            }
87
            else {
88
                $_a = $_a[$key];
89
            }
90
        }
91
92
        return $_a;
93
    }
94
95
    /**
96
     * Merges any number of arrays / parameters recursively, replacing entries with string keys with values from latter
97
     * arrays.
98
     *
99
     * If the entry or the next value to be assigned is an array, then it automagically treats both arguments as an
100
     * array. Numeric entries are appended, not replaced, if the value doesn't already exist in the merged array
101
     * otherwise they're skipped.
102
     *
103
     * @return array The merged array
104
     */
105
    public static function mergeRecursiveDistinct()
106
    {
107
        $prepare = function ($arg) {
108
            return ! is_array($arg) ? array($arg) : $arg;
109
        };
110
        $arguments = func_get_args();
111
        $base = $prepare(array_shift($arguments));
112
113
        foreach ($arguments as $argument) {
114
115
            $argument = $prepare($argument);
116
117
            foreach ($argument as $key => $value) {
118
                if ( ! is_numeric($key)) {
119
                    if ( ! array_key_exists($key, $base)
120
                        || ( ! is_array($value) && ! is_array($base[$key]))
121
                    ) {
122
                        $base[$key] = $value;
123
                    }
124
                    else {
125
                        $base[$key] = self::mergeRecursiveDistinct($base[$key], $value);
126
                    }
127
                }
128
                elseif ( ! in_array($value, $base)) {
129
                    $base[] = $value;
130
                }
131
            }
132
        }
133
134
        return $base;
135
    }
136
137
    /**
138
     * Tests if $array is an associative array.
139
     *
140
     * @param  array   $array
141
     * @return boolean        Returns true if just one key is a string, false otherwise.
142
     */
143
    public static function isAssociative(array $array)
144
    {
145
        return count(array_filter(array_keys($array), 'is_string')) > 0;
146
    }
147
}
148