Passed
Push — master ( 01e41e...21756f )
by Théo
02:37
created

functions.php ➔ create_reflector()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the humbug/php-scoper package.
7
 *
8
 * Copyright (c) 2017 Théo FIDRY <[email protected]>,
9
 *                    Pádraic Brady <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Humbug\PhpScoper;
16
17
use AppendIterator;
18
use ArrayIterator;
19
use Humbug\PhpScoper\Console\Application;
20
use Humbug\PhpScoper\Console\Command\AddPrefixCommand;
21
use Humbug\PhpScoper\Console\Command\InitCommand;
22
use Humbug\PhpScoper\Console\Command\SelfUpdateCommand;
23
use Humbug\PhpScoper\Scoper\Composer\InstalledPackagesScoper;
24
use Humbug\PhpScoper\Scoper\Composer\JsonFileScoper;
25
use Humbug\PhpScoper\Scoper\NullScoper;
26
use Humbug\PhpScoper\Scoper\PatchScoper;
27
use Humbug\PhpScoper\Scoper\PhpScoper;
28
use Humbug\PhpScoper\Scoper\TraverserFactory;
29
use Humbug\SelfUpdate\Exception\RuntimeException as SelfUpdateRuntimeException;
30
use Humbug\SelfUpdate\Updater;
31
use Iterator;
32
use IteratorAggregate;
33
use PackageVersions\Versions;
34
use PhpParser\Node;
35
use PhpParser\Parser;
36
use PhpParser\ParserFactory;
37
use Roave\BetterReflection\Reflector\ClassReflector;
38
use Roave\BetterReflection\SourceLocator\Ast\Locator;
39
use Roave\BetterReflection\SourceLocator\Type\MemoizingSourceLocator;
40
use Roave\BetterReflection\SourceLocator\Type\PhpInternalSourceLocator;
41
use Symfony\Component\Console\Application as SymfonyApplication;
42
use Symfony\Component\Filesystem\Filesystem;
43
44
// TODO: register this file to the list of functions if possible to be autoloaded
45
46
/**
47
 * @private
48
 */
49
function create_application(): SymfonyApplication
50
{
51
    $app = new Application('PHP Scoper', get_version());
52
53
    $app->addCommands([
54
        new AddPrefixCommand(
55
            new Filesystem(),
56
            create_scoper()
57
        ),
58
        new InitCommand(),
59
    ]);
60
61
    if ('phar:' === substr(__FILE__, 0, 5)) {
62
        try {
63
            $updater = new Updater();
64
        } catch (SelfUpdateRuntimeException $e) {
65
            /* Allow E2E testing of unsigned phar */
66
            $updater = new Updater(null, false);
67
        }
68
        $app->add(
69
            new SelfUpdateCommand(
70
                $updater
71
            )
72
        );
73
    }
74
75
    return $app;
76
}
77
78
/**
79
 * @private
80
 */
81
function get_version(): string
82
{
83
    $rawVersion = Versions::getVersion('humbug/php-scoper');
84
85
    list($prettyVersion, $commitHash) = explode('@', $rawVersion);
86
87
    return (1 === preg_match('/9{7}/', $prettyVersion)) ? $commitHash : $prettyVersion;
88
}
89
90
/**
91
 * @private
92
 */
93
function create_scoper(): Scoper
94
{
95
    return new PatchScoper(
96
        new PhpScoper(
97
            create_parser(),
98
            new JsonFileScoper(
99
                new InstalledPackagesScoper(
100
                    new NullScoper()
101
                )
102
            ),
103
            new TraverserFactory(create_reflector())
104
        )
105
    );
106
}
107
108
/**
109
 * @private
110
 */
111
function create_parser(): Parser
112
{
113
    return (new ParserFactory())->create(ParserFactory::ONLY_PHP7);
114
}
115
116
function create_reflector(): Reflector
117
{
118
    $phpParser = create_parser();
119
    $astLocator = new Locator($phpParser);
120
121
    return new Reflector(
122
        new ClassReflector(
123
            new MemoizingSourceLocator(
124
                new PhpInternalSourceLocator($astLocator)
125
            )
126
        )
127
    );
128
}
129
130
/**
131
 * @param string[] $paths Absolute paths
132
 *
133
 * @return string
134
 */
135
function get_common_path(array $paths): string
136
{
137
    if (0 === count($paths)) {
138
        return '';
139
    }
140
141
    $lastOffset = 1;
142
    $common = DIRECTORY_SEPARATOR;
143
144
    while (false !== ($index = strpos($paths[0], DIRECTORY_SEPARATOR, $lastOffset))) {
145
        $dirLen = $index - $lastOffset + 1;
146
        $dir = substr($paths[0], $lastOffset, $dirLen);
147
148
        foreach ($paths as $path) {
149
            if (substr($path, $lastOffset, $dirLen) !== $dir) {
150 View Code Duplication
                if (0 < strlen($common) && DIRECTORY_SEPARATOR === $common[strlen($common) - 1]) {
151
                    $common = substr($common, 0, strlen($common) - 1);
152
                }
153
154
                return $common;
155
            }
156
        }
157
158
        $common .= $dir;
159
        $lastOffset = $index + 1;
160
    }
161
162
    $common = substr($common, 0, -1);
163
164 View Code Duplication
    if (0 < strlen($common) && DIRECTORY_SEPARATOR === $common[strlen($common) - 1]) {
165
        $common = substr($common, 0, strlen($common) - 1);
166
    }
167
168
    return $common;
169
}
170
171
/**
172
 * In-house clone functions. Does a partial clone that should be enough to provide the immutability required in some
173
 * places for the scoper. It however does not guarantee a deep cloning as would be horribly slow for no good reasons.
174
 * A better alternative would be to find a way to push immutability upstream in PHP-Parser directly.
175
 *
176
 * @param Node $node
177
 *
178
 * @return Node
179
 */
180
function clone_node(Node $node): Node
181
{
182
    $clone = deep_clone($node);
183
184
    foreach ($node->getAttributes() as $key => $attribute) {
185
        $clone->setAttribute($key, $attribute);
186
    }
187
188
    return $clone;
189
}
190
191
/**
192
 * @param mixed $node
193
 *
194
 * @return mixed
195
 *
196
 * @internal
197
 */
198
function deep_clone($node)
199
{
200
    if (is_array($node)) {
201
        return array_map(__FUNCTION__, $node);
202
    }
203
204
    if (null === $node || is_scalar($node)) {
205
        return $node;
206
    }
207
208
    return unserialize(serialize($node));
209
}
210
211
function iterables_to_iterator(iterable ...$iterables): Iterator
212
{
213
    $iterator = new AppendIterator();
214
215
    foreach ($iterables as $iterable) {
216
        if (is_array($iterable)) {
217
            $iterator->append(new ArrayIterator($iterable));
218
        } elseif ($iterable instanceof IteratorAggregate) {
219
            $iterator->append($iterable->getIterator());
220
        } else {
221
            /* @var Iterator $iterable */
222
            $iterator->append($iterable);
223
        }
224
    }
225
226
    return $iterator;
227
}
228