Completed
Push — master ( e44765...ab86c3 )
by Andrii
04:18
created

Helper::mergeConfig()   D

Complexity

Conditions 9
Paths 3

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 4.909
c 0
b 0
f 0
ccs 0
cts 24
cp 0
cc 9
eloc 17
nc 3
nop 0
crap 90
1
<?php
2
3
/*
4
 * Composer plugin for config assembling
5
 *
6
 * @link      https://github.com/hiqdev/composer-config-plugin
7
 * @package   composer-config-plugin
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2016, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hiqdev\composer\config;
13
14
use Closure;
15
use ReflectionFunction;
16
17
/**
18
 * Helper class.
19
 *
20
 * @author Andrii Vasyliev <[email protected]>
21
 */
22
class Helper
23
{
24
    /**
25
     * Merges two or more arrays into one recursively.
26
     * Based on Yii2 yii\helpers\BaseArrayHelper::merge.
27
     * @return array the merged array
28
     */
29
    public static function mergeConfig()
30
    {
31
        $args = func_get_args();
32
        $res = array_shift($args);
33
        foreach ($args as $items) {
34
            if (!is_array($items)) {
35
                continue;
36
            }
37
            foreach ($items as $k => $v) {
38
                if (is_int($k)) {
39
                    if (isset($res[$k])) {
40
                        $res[] = $v;
41
                    } else {
42
                        $res[$k] = $v;
43
                    }
44
                } elseif (is_array($v) && isset($res[$k]) && is_array($res[$k])) {
45
                    $res[$k] = self::mergeConfig($res[$k], $v);
46
                } else {
47
                    $res[$k] = $v;
48
                }
49
            }
50
        }
51
52
        return $res;
53
    }
54
55
    /**
56
     * Dumps closure object to string.
57
     * Based on http://www.metashock.de/2013/05/dump-source-code-of-closure-in-php/.
58
     * @param Closure $closure
59
     * @return string
60
     */
61
    public static function dumpClosure(Closure $closure)
62
    {
63
        $res = 'function (';
64
        $fun = new ReflectionFunction($closure);
65
        $args = [];
66
        foreach ($fun->getParameters() as $arg) {
67
            $str = '';
68
            if ($arg->isArray()) {
69
                $str .= 'array ';
70
            } elseif ($arg->getClass()) {
71
                $str .= $arg->getClass()->name . ' ';
72
            }
73
            if ($arg->isPassedByReference()) {
74
                $str .= '&';
75
            }
76
            $str .= '$' . $arg->name;
77
            if ($arg->isOptional()) {
78
                $str .= ' = ' . var_export($arg->getDefaultValue(), true);
79
            }
80
            $args[] = $str;
81
        }
82
        $res .= implode(', ', $args);
83
        $res .= ') {' . PHP_EOL;
84
        $lines = file($fun->getFileName());
85
        for ($i = $fun->getStartLine(); $i < $fun->getEndLine(); ++$i) {
86
            $res .= $lines[$i];
87
        }
88
89
        return rtrim($res, "\n ,");
90
    }
91
92
    /**
93
     * Returns a parsable string representation of given value.
94
     * In contrast to var_dump outputs Closures as PHP code.
95
     * @param mixed $value
96
     * @return string
97
     */
98
    public static function exportVar($value)
99
    {
100
        $closures = self::collectClosures($value);
101
        $res = var_export($value, true);
102
        if (!empty($closures)) {
103
            $subs = [];
104
            foreach ($closures as $key => $closure) {
105
                $subs["'" . $key . "'"] = self::dumpClosure($closure);
106
            }
107
            $res = strtr($res, $subs);
108
        }
109
110
        return $res;
111
    }
112
113
    /**
114
     * Collects closures from given input.
115
     * Substitutes closures with a tag.
116
     * @param mixed $input will be changed
117
     * @return array array of found closures
118
     */
119
    private static function collectClosures(&$input)
120
    {
121
        static $closureNo = 1;
122
        $closures = [];
123
        if (is_array($input)) {
124
            foreach ($input as &$value) {
125
                if (is_array($value) || $value instanceof Closure) {
126
                    $closures = array_merge($closures, self::collectClosures($value));
127
                }
128
            }
129
        } elseif ($input instanceof Closure) {
130
            ++$closureNo;
131
            $key = "--==<<[[((Closure#$closureNo))]]>>==--";
132
            $closures[$key] = $input;
133
            $input = $key;
134
        }
135
136
        return $closures;
137
    }
138
}
139