Passed
Branch master (c976c6)
by Théo
03:51
created

ScoperAutoloadGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
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\Autoload;
16
17
use Humbug\PhpScoper\Whitelist;
18
use PhpParser\Node\Name\FullyQualified;
19
use function array_column;
20
use function array_map;
21
use function array_unshift;
22
use function chr;
23
use function sprintf;
24
use function str_repeat;
25
use function str_replace;
26
use function strpos;
27
28
final class ScoperAutoloadGenerator
29
{
30
    private $whitelist;
31
    private $eol;
32
33 9
    public function __construct(Whitelist $whitelist)
34
    {
35 9
        $this->whitelist = $whitelist;
36 9
        $this->eol = chr(10);
37
    }
38
39 9
    public function dump(): string
40
    {
41 9
        $whitelistedFunctions = $this->whitelist->getRecordedWhitelistedFunctions();
42
43 9
        $hasNamespacedFunctions = $this->hasNamespacedFunctions($whitelistedFunctions);
44
45 9
        $statements = implode(
46 9
            $this->eol,
47 9
            $this->createClassAliasStatements(
48 9
                $this->whitelist->getRecordedWhitelistedClasses(),
49 9
                $hasNamespacedFunctions)
50
            )
51 9
            .$this->eol
52 9
            .$this->eol
53
        ;
54 9
        $statements .= implode(
55 9
            $this->eol,
56 9
            $this->createFunctionAliasStatements(
57 9
                $whitelistedFunctions,
58 9
                $hasNamespacedFunctions
59
            )
60
        );
61
62 9
        if ($hasNamespacedFunctions) {
63
            $dump = <<<PHP
64
<?php
65
66
// scoper-autoload.php @generated by PhpScoper
67
68
namespace {
69
    \$loader = require_once __DIR__.'/autoload.php';
70
}
71
72 3
$statements
73
74
namespace {
75
    return \$loader;
76
}
77
78
PHP;
79
        } else {
80
            $dump = <<<PHP
81
<?php
82
83
// scoper-autoload.php @generated by PhpScoper
84
85
\$loader = require_once __DIR__.'/autoload.php';
86
87 6
$statements
88
89
return \$loader;
90
91
PHP;
92
        }
93
94 9
        $dump = $this->cleanAutoload($dump);
95
96 9
        return $dump;
97
    }
98
99
    /**
100
     * @return string[]
101
     */
102 9
    private function createClassAliasStatements(array $whitelistedClasses, bool $hasNamespacedFunctions): array
103
    {
104 9
        $statements = array_map(
105
            static function (string $prefixedClass): string {
106 3
                return sprintf(
107 3
                    'class_exists(\'%s\');',
108 3
                    $prefixedClass
109
                );
110 9
            },
111 9
            array_column(
112 9
                $whitelistedClasses,
113 9
                1
114
            )
115
        );
116
117 9
        if ([] === $statements) {
118 6
            return $statements;
119
        }
120
121 3
        if ($hasNamespacedFunctions) {
122 1
            $statements = array_map(
123
                static function (string $statement): string {
124 1
                    return str_repeat(' ', 4).$statement;
125 1
                },
126 1
                $statements
127
            );
128
129 1
            array_unshift($statements, 'namespace {');
130 1
            $statements[] = '}'.$this->eol;
131
        }
132
133 3
        array_unshift(
134 3
            $statements,
135
            <<<'EOF'
136 3
// Aliases for the whitelisted classes. For more information see:
137
// https://github.com/humbug/php-scoper/blob/master/README.md#class-whitelisting
138
EOF
139
        );
140
141 3
        return $statements;
142
    }
143
144
    /**
145
     * @return string[]
146
     */
147 9
    private function createFunctionAliasStatements(array $whitelistedFunctions, bool $hasNamespacedFunctions): array
148
    {
149 9
        $statements = array_map(
150
            static function (array $node) use ($hasNamespacedFunctions): string {
151
                $original = new FullyQualified($node[0]);
152
                $alias = new FullyQualified($node[1]);
153
154
                if ($hasNamespacedFunctions) {
155 5
                    $namespace = $original->slice(0, -1);
156
                    $functionName = null === $namespace ? $original->toString() : $original->slice(1)->toString();
157 5
158 5
                    return sprintf(
159
                        <<<'PHP'
160 5
namespace %s{
161 3
    if (!function_exists('%s')) {
162 3
        function %s(%s) {
163
            return \%s(...func_get_args());
164 3
        }
165
    }
166 3
}
167
PHP
168
                        ,
169
                        null === $namespace ? '' : $namespace->toString().' ',
170
                        $original->toString(),
171
                        $functionName,
172
                        '__autoload' === $functionName ? '$className' : '',
173
                        $alias->toString()
174
                    );
175 3
                }
176 3
177 3
                return sprintf(
178 3
                    <<<'PHP'
179 3
if (!function_exists('%1$s')) {
180
    function %1$s(%2$s) {
181
        return \%3$s(...func_get_args());
182
    }
183 2
}
184
PHP
185 2
                    ,
186
                    $original,
187
                    '__autoload' === (string) $original ? '$className' : '',
188
                    $alias
189
                );
190
            },
191
            $whitelistedFunctions
192 2
        );
193 2
194 2
        if ([] === $statements) {
195
            return $statements;
196 9
        }
197 9
198
        array_unshift(
199
            $statements,
200 9
            <<<'EOF'
201 4
// Functions whitelisting. For more information see:
202
// https://github.com/humbug/php-scoper/blob/master/README.md#functions-whitelisting
203
EOF
204 5
        );
205 5
206
        return $statements;
207 5
    }
208
209
    private function hasNamespacedFunctions(array $functions): bool
210
    {
211
        foreach ($functions as [$original, $alias]) {
212 5
            /*
213
             * @var string
214
             * @var string $alias
215 9
             */
216
            if (false !== strpos($original, '\\')) {
217 9
                return true;
218
            }
219
        }
220
221
        return false;
222 5
    }
223 3
224
    private function cleanAutoload(string $dump): string
225
    {
226
        $cleanedDump = $dump;
227 6
228
        do {
229
            $dump = $cleanedDump;
230 9
            $cleanedDump = str_replace("\n\n\n", "\n\n", $dump);
231
        } while ($cleanedDump !== $dump);
232 9
233
        return $dump;
234
    }
235
}
236