Completed
Push — master ( 7e6e4f...faf6ce )
by Andrii
16:25
created

Helper::className()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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