SymbolRegistry::matches()   A
last analyzed

Complexity

Conditions 5
Paths 8

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 10
nc 8
nop 1
dl 0
loc 18
rs 9.6111
c 1
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\Symbol;
16
17
use InvalidArgumentException;
18
use function array_key_exists;
19
use function array_keys;
20
use function array_map;
21
use function array_pop;
22
use function array_unique;
23
use function explode;
24
use function implode;
25
use function ltrim;
26
use function Safe\array_flip;
27
use function Safe\preg_match;
28
use function strtolower;
29
use function trim;
30
use const SORT_STRING;
31
32
final class SymbolRegistry
33
{
34
    /**
35
     * @var array<string, mixed>
36
     */
37
    private array $names;
38
39
    /**
40
     * @var list<string>
0 ignored issues
show
Bug introduced by
The type Humbug\PhpScoper\Symbol\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
41
     */
42
    private array $regexes;
43
44
    private bool $constants;
45
46
    /**
47
     * @param string[] $names
48
     * @param string[] $regexes
49
     */
50
    public static function create(
51
        array $names = [],
52
        array $regexes = []
53
    ): self {
54
        return new self(
55
            array_map(
56
                static fn (string $name) => strtolower(trim($name, '\\')),
57
                $names,
58
            ),
59
            array_unique($regexes, SORT_STRING),
60
            false,
61
        );
62
    }
63
64
    /**
65
     * Unlike classes & functions, constants are not case-insensitive (although
66
     * the namespace part _is_). I.e. \Acme\FOO = \ACME\FOO but Acme\FOO ≠ Acme\Foo.
67
     *
68
     * @param string[] $names
69
     * @param string[] $regexes
70
     */
71
    public static function createForConstants(
72
        array $names = [],
73
        array $regexes = []
74
    ): self {
75
        return new self(
76
            array_map(
77
                static fn (string $name) => self::lowerCaseConstantName(
78
                    trim($name, '\\'),
79
                ),
80
                $names,
81
            ),
82
            array_unique($regexes, SORT_STRING),
83
            true,
84
        );
85
    }
86
87
    /**
88
     * @param list<string> $names
89
     * @param list<string> $regexes
90
     */
91
    private function __construct(
92
        array $names,
93
        array $regexes,
94
        bool $constants
95
    ) {
96
        $this->names = array_flip($names);
0 ignored issues
show
Deprecated Code introduced by
The function Safe\array_flip() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

96
        $this->names = /** @scrutinizer ignore-deprecated */ array_flip($names);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
97
        $this->regexes = $regexes;
0 ignored issues
show
Documentation Bug introduced by
It seems like $regexes of type array is incompatible with the declared type Humbug\PhpScoper\Symbol\list of property $regexes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
98
        $this->constants = $constants;
99
    }
100
101
    public function matches(string $symbol): bool
102
    {
103
        $originalSymbol = ltrim($symbol, '\\');
104
        $symbol = $this->constants
105
            ? self::lowerCaseConstantName($originalSymbol)
106
            : strtolower($originalSymbol);
107
108
        if (array_key_exists($symbol, $this->names)) {
109
            return true;
110
        }
111
112
        foreach ($this->regexes as $regex) {
113
            if (preg_match($regex, $originalSymbol)) {
114
                return true;
115
            }
116
        }
117
118
        return false;
119
    }
120
121
    public function merge(self $registry): self
122
    {
123
        if ($this->constants !== $registry->constants) {
124
            throw new InvalidArgumentException('Cannot merge registries of different symbol types');
125
        }
126
127
        $args = [
128
            [
129
                ...$this->getNames(),
130
                ...$registry->getNames(),
131
            ],
132
            [
133
                ...$this->getRegexes(),
134
                ...$registry->getRegexes(),
135
            ],
136
        ];
137
138
        return $this->constants
139
            ? self::createForConstants(...$args)
0 ignored issues
show
Bug introduced by
$args is expanded, but the parameter $names of Humbug\PhpScoper\Symbol\...y::createForConstants() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

139
            ? self::createForConstants(/** @scrutinizer ignore-type */ ...$args)
Loading history...
140
            : self::create(...$args);
0 ignored issues
show
Bug introduced by
$args is expanded, but the parameter $names of Humbug\PhpScoper\Symbol\SymbolRegistry::create() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
            : self::create(/** @scrutinizer ignore-type */ ...$args);
Loading history...
141
    }
142
143
    /**
144
     * @internal
145
     *
146
     * @return list<string>
147
     */
148
    public function getNames(): array
149
    {
150
        return array_keys($this->names);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_keys($this->names) returns the type array which is incompatible with the documented return type Humbug\PhpScoper\Symbol\list.
Loading history...
151
    }
152
153
    /**
154
     * @internal
155
     *
156
     * @erturn list<string>
157
     */
158
    public function getRegexes(): array
159
    {
160
        return $this->regexes;
161
    }
162
163
    /**
164
     * Transforms the constant FQ name "Acme\Foo\X" to "acme\foo\X" since the
165
     * namespace remains case-insensitive for constants regardless of whether
166
     * constants actually are case-insensitive.
167
     */
168
    private static function lowerCaseConstantName(string $name): string
169
    {
170
        $parts = explode('\\', $name);
171
172
        $lastPart = array_pop($parts);
173
174
        $parts = array_map('strtolower', $parts);
175
176
        $parts[] = $lastPart;
177
178
        return implode('\\', $parts);
179
    }
180
}
181