Passed
Pull Request — master (#103)
by Dmitriy
02:29
created

MemoizedCombinedRegexp::matches()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 0
cts 3
cp 0
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Strings;
6
7
/**
8
 * `CombinedRegexp` optimizes matching of multiple regular expressions.
9
 * Read more about the concept in
10
 * {@see https://nikic.github.io/2014/02/18/Fast-request-routing-using-regular-expressions.html}.
11
 */
12
final class MemoizedCombinedRegexp
13
{
14
    private CombinedRegexp $combinedRegexp;
15
16
    private array $results = [];
17
18
    /**
19
     * @param string[] $patterns Regular expressions to combine.
20
     * @param string $flags Flags to apply to all regular expressions.
21
     */
22
    public function __construct(
23
        private array $patterns,
24
        string $flags = ''
25
    ) {
26
        $this->combinedRegexp = new CombinedRegexp($patterns, $flags);
27
    }
28
29
    /**
30
     * @return string The compiled pattern.
31
     */
32
    public function getCompiledPattern(): string
33
    {
34
        return $this->combinedRegexp->getCompiledPattern();
35
    }
36
37
    /**
38
     * Returns `true` whether the given string matches any of the patterns, `false` - otherwise.
39
     */
40
    public function matches(string $string): bool
41
    {
42
        $this->evaluate($string);
43
44
        return $this->results[$string]['matches'];
45
    }
46
47
    /**
48
     * Returns pattern that matches the given string.
49
     * @throws \Exception if the string does not match any of the patterns.
50
     */
51
    public function getMatchingPattern(string $string): string
52
    {
53
        $this->evaluate($string);
54
55
        return $this->patterns[$this->getMatchingPatternPosition($string)];
56
    }
57
58
    /**
59
     * Returns position of the pattern that matches the given string.
60
     * @throws \Exception if the string does not match any of the patterns.
61
     */
62
    public function getMatchingPatternPosition(string $string): int
63
    {
64
        $this->evaluate($string);
65
66
        return $this->results[$string]['position'] ?? throw new \Exception(
67
            sprintf(
68
                'Failed to match pattern "%s" with string "%s".',
69
                $this->getCompiledPattern(),
70
                $string,
71
            )
72
        );
73
    }
74
75
    protected function evaluate(string $string): void
76
    {
77
        if (isset($this->results[$string])) {
78
            return;
79
        }
80
        try {
81
            $position = $this->combinedRegexp->getMatchingPatternPosition($string);
82
83
            $this->results[$string]['matches'] = true;
84
            $this->results[$string]['position'] = $position;
85
        } catch (\Exception) {
86
            $this->results[$string]['matches'] = false;
87
        }
88
    }
89
}
90