Completed
Push — master ( ab86c3...b85299 )
by Andrii
01:45
created

Helper::exportVar()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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